excel_plus 2.0.0 copy "excel_plus: ^2.0.0" to clipboard
excel_plus: ^2.0.0 copied to clipboard

Fast, low-memory Excel (.xlsx) library for Dart and Flutter to read, create, edit, and style spreadsheets. A drop-in replacement for the excel package.

excel_plus — fast, low-memory Excel (.xlsx) library for Dart and Flutter

pub version pub points pub likes GitHub stars GitHub forks GitHub issues CI status Last commit License: MIT Dart

Excel (.xlsx) Library for Dart & Flutter #

excel_plus is a fast, low-memory, non-UI Dart library for creating, reading, editing, and styling Microsoft Excel .xlsx spreadsheets. It works in plain Dart and in Flutter apps, on the VM, Web (JS & WASM), and mobile. excel_plus is a source-compatible drop-in replacement for the excel package — change one import and your existing code keeps working, with better performance on large workbooks.

Overview #

excel_plus reads and writes the Office Open XML .xlsx format used by Microsoft Excel, Google Sheets, and LibreOffice Calc. It parses workbooks with a streaming (SAX) reader and loads each sheet lazily, so memory stays low even on large files, and it reuses untouched parts of a workbook byte-for-byte when saving.

What you can do with it:

  • Read and parse existing .xlsx files, or create new Excel workbooks from scratch.
  • Edit cells, rows, columns, and multiple sheets, then save back to .xlsx.
  • Style spreadsheets — fonts, colors, fills, borders, alignment, number formats, and merged cells.

A styled Excel sheet produced by excel_plus: a merged green title, a bold header row, colored Paid/Due status cells, borders, and currency formatting

Performance #

excel_plus is built for large workbooks: a streaming SAX parser instead of full-DOM parsing, lazy per-sheet loading, O(1) reverse indexes for styles and shared strings, and byte-for-byte reuse of untouched workbook parts on save.

It comfortably handles workbooks with millions of cells. Here is a head-to-head against the original excel package — same machine, same workload:

excel_plus vs excel — encode, decode and peak memory at 1M and 5M cells

Workload Encode (excel → excel_plus) Decode Peak memory Create
5,000,000 cells 48.8 s → 9.2 s · 5.3× 56.8 s → 19.5 s · 2.9× 12.0 GB → 2.6 GB · 4.6× ≈ equal
1,000,000 cells 9.4 s → 1.6 s · 5.8× 10.9 s → 3.7 s · 3.0× 2.5 GB → 0.7 GB · 3.5× ≈ equal
10,000 cells 184 ms → 41 ms · 4.5× 141 ms → 75 ms · 1.9× ≈ equal* ≈ equal
500 cells 54 ms → 16 ms · 3.3× 32 ms → 19 ms · 1.7× ≈ equal* ≈ equal

* Below ~100k cells peak memory is dominated by the Dart VM baseline (~250 MB), so it is comparable; the gap widens with size (3.5× at 1M → 4.6× at 5M, where excel needed ~12 GB RAM). Create time is within noise — both build cells the same way.

The two libraries pin conflicting archive/xml majors, so they can't run in one program; each harness lives in its own package under benchmark/compare/. Timings vary by hardware — reproduce both on your own machine:

cd benchmark/compare/excel_baseline   && dart pub get && dart run bin/benchmark.dart
cd ../excel_plus_bench                && dart pub get && dart run bin/benchmark.dart

Table of contents #

Key features #

  • ✅ Read & write .xlsx
  • ✅ Create workbooks
  • ✅ Multiple sheets
  • ✅ All cell types
  • ✅ Formula evaluation
  • ✅ Cell styling
  • ✅ Number formats
  • ✅ Hyperlinks
  • ✅ Data validation
  • ✅ Conditional formatting
  • ✅ Freeze panes
  • ✅ Autofilter
  • ✅ Sheet & workbook protection
  • ✅ Defined names
  • ✅ Images
  • ✅ Page & print setup
  • ✅ Grouping & outline
  • ✅ Comments / notes
  • ✅ Excel tables (ListObjects)
  • ✅ Charts (column, bar, line, area, pie, doughnut, scatter)
  • ✅ Pivot tables (row / column / page / nested fields + measures)
  • ✅ Rich text (read & write)
  • ✅ Theme & indexed colours
  • ✅ Merge & unmerge
  • ✅ Rows & columns
  • ✅ Column width / row height
  • ✅ Find & replace
  • ✅ Typed exceptions
  • ✅ Cross-platform
  • ✅ Source-compatible drop-in

Limitations #

  • ❌ Long-tail / engineering formula functions
  • ❌ Split panes
  • ❌ Chart read-back (authoring is supported)
  • ❌ Pivot typed read-back (authoring — incl. row/column/page/nested fields — is supported; existing pivots are preserved on round-trip)

Roadmap #

  • ✅ Worksheet features (hyperlinks, validation, conditional formatting, panes, autofilter, protection, named ranges) — 1.0.0
  • ✅ Theme & indexed colours, rich-text write, error values — 1.0.0
  • ✅ Images, comments, page & print setup, grouping — 1.1.0
  • ✅ Formula-evaluation engine (~130 functions) — 1.1.0
  • ✅ Excel tables / ListObjects — 1.1.0
  • ✅ Charts (7 types) — 1.1.0
  • ✅ Array-formula spilling (recalculate) — 1.1.0
  • ✅ Pivot tables (row / column / page / nested fields + measures) — 1.1.0
  • ✅ Typed exception hierarchy (ExcelException + subtypes) — 2.0.0

See the formula functions reference for the full list of supported and planned functions.

Shipped changes are tracked in the changelog, and the direction is driven by what users request on the issue tracker.

Error handling #

Opening or saving a file throws a typed, catchable ExcelException. Catch the base type for any failure, or narrow to a specific kind — each carries a message, an optional part (the package part involved), and an optional cause:

try {
  final excel = Excel.decodeBytes(bytes);
  // ... edit ...
  excel.save();
} on ExcelArchiveException catch (e) {
  // Not a readable .xlsx (bad ZIP, or a required part is missing).
  print('Not a usable file: ${e.message}');
} on ExcelFormatException catch (e) {
  // A valid ZIP, but its XML is malformed/inconsistent.
  print('Corrupt content in ${e.part}: ${e.message}');
} on ExcelException catch (e) {
  // Any other excel_plus failure (e.g. ExcelEncodeException on save).
  print('Workbook error: ${e.message}');
}

Invalid arguments you pass to the API (a negative cell index, an empty table name, an out-of-range row) throw ArgumentError, the standard Dart type for programming errors — they are not ExcelExceptions. A malformed formula is not thrown either: it evaluates to an #ERROR! cell value.

Example #

Open the live demo

▶ Try the live demo — build, style and export real .xlsx files right in your browser. No install needed.

A complete, runnable sample lives in the example/ directory. Clone the repository and run it, or copy any snippet from Getting started below.

Installation #

dart pub add excel_plus
# or, in a Flutter app:
flutter pub add excel_plus

Then import it:

import 'package:excel_plus/excel_plus.dart';

Getting started #

Create a simple Excel document #

final excel = Excel.createExcel(); // a new workbook with one default sheet
final sheet = excel['Sheet1'];

sheet.updateCell(CellIndex.indexByString('A1'), TextCellValue('Hello, world!'));

final bytes = excel.save(); // List<int> of the .xlsx file

Add text, number, boolean, and date values #

sheet.updateCell(CellIndex.indexByString('A1'), TextCellValue('Name'));
sheet.updateCell(CellIndex.indexByString('B1'), IntCellValue(42));
sheet.updateCell(CellIndex.indexByString('C1'), DoubleCellValue(3.14));
sheet.updateCell(CellIndex.indexByString('D1'), BoolCellValue(true));
sheet.updateCell(CellIndex.indexByString('E1'), DateCellValue(year: 2026, month: 6, day: 9));
sheet.updateCell(CellIndex.indexByString('F1'), TimeCellValue(hour: 9, minute: 30, second: 0));
sheet.updateCell(
  CellIndex.indexByString('G1'),
  DateTimeCellValue(year: 2026, month: 6, day: 9, hour: 9, minute: 30),
);

Add formulas #

Formulas are stored and round-tripped as text, and excel_plus can also evaluate them: sheet.evaluate(cell) returns the computed value, and excel.recalculate() writes each formula's result into its cached value (so a saved file shows results). See the formula functions reference for the ~130 built-in functions.

sheet.updateCell(CellIndex.indexByString('A1'), IntCellValue(10));
sheet.updateCell(CellIndex.indexByString('A2'), IntCellValue(20));
sheet.updateCell(CellIndex.indexByString('A3'), FormulaCellValue('SUM(A1:A2)'));

// ...or set a formula on an existing cell:
sheet.cell(CellIndex.indexByString('A4')).setFormula('AVERAGE(A1:A2)');

// Evaluate one cell, or recompute the whole workbook:
print(sheet.evaluate(CellIndex.indexByString('A3'))); // 30
excel.recalculate(); // store every formula's computed result

// Register a custom function, callable as =TRIPLE(A1):
excel.formula.registerFunction('TRIPLE', (args) {
  final v = args.isEmpty ? null : args.first;
  return IntCellValue((v is IntCellValue ? v.value : 0) * 3);
});

Read an existing Excel file #

import 'dart:io';

final bytes = File('input.xlsx').readAsBytesSync();
final excel = Excel.decodeBytes(bytes);

for (final sheetName in excel.tables.keys) {
  for (final row in excel[sheetName].rows) {
    print(row.map((cell) => cell?.value).toList());
  }
}

Read a single cell #

final cell = excel['Sheet1'].cell(CellIndex.indexByString('B2'));
print(cell.value); // a typed CellValue: TextCellValue, IntCellValue, ...

Style a cell — font, color, fill, alignment #

sheet.updateCell(
  CellIndex.indexByString('A1'),
  TextCellValue('Header'),
  cellStyle: CellStyle(
    bold: true,
    italic: true,
    fontSize: 14,
    fontColorHex: ExcelColor.white,
    backgroundColorHex: ExcelColor.fromHexString('#21A366'),
    horizontalAlign: HorizontalAlign.Center,
    verticalAlign: VerticalAlign.Center,
  ),
);

Add borders #

sheet.cell(CellIndex.indexByString('A1')).cellStyle = CellStyle(
  leftBorder: Border(borderStyle: BorderStyle.Thin),
  rightBorder: Border(borderStyle: BorderStyle.Thin),
  topBorder: Border(borderStyle: BorderStyle.Medium),
  bottomBorder: Border(borderStyle: BorderStyle.Medium, borderColorHex: ExcelColor.red),
);

Apply number formats #

// Currency with a thousands separator (custom format code).
sheet.updateCell(
  CellIndex.indexByString('A1'),
  DoubleCellValue(12500.5),
  cellStyle: CellStyle(numberFormat: NumFormat.custom(formatCode: r'$#,##0.00')),
);

// Percentage (built-in format).
sheet.updateCell(
  CellIndex.indexByString('A2'),
  DoubleCellValue(0.125),
  cellStyle: CellStyle(numberFormat: NumFormat.standard_10), // 0.00%
);

Merge and unmerge cells #

sheet.merge(
  CellIndex.indexByString('A1'),
  CellIndex.indexByString('D1'),
  customValue: TextCellValue('Merged title'),
);

sheet.unMerge('A1:D1');

Insert and delete rows and columns #

sheet.insertRow(2);    // insert a blank row at index 2
sheet.removeRow(5);    // delete row 5
sheet.insertColumn(1); // insert a blank column at index 1
sheet.removeColumn(3); // delete column 3

Append a row #

sheet.appendRow([
  TextCellValue('Alice'),
  IntCellValue(30),
  DoubleCellValue(12500.0),
]);

Column width, row height, and auto-fit #

sheet.setColumnWidth(0, 24.0);
sheet.setRowHeight(0, 32.0);
sheet.setColumnAutoFit(1);

Work with multiple sheets #

final excel = Excel.createExcel();
excel['Sales'].updateCell(CellIndex.indexByString('A1'), TextCellValue('Q1'));
excel['Inventory'].updateCell(CellIndex.indexByString('A1'), TextCellValue('SKU'));

excel.rename('Sales', 'Revenue');
excel.copy('Revenue', 'Revenue (Backup)');
excel.delete('Inventory');
excel.setDefaultSheet('Revenue');

Find and replace #

// Within one sheet — returns the number of replacements made.
final count = excel['Sheet1'].findAndReplace('draft', 'final');

// Across a named sheet via the workbook.
excel.findAndReplace('Sheet1', 'old', 'new');

Save the workbook #

// 1) As bytes.
final List<int>? bytes = excel.save();

// 2) To a file (Dart VM / desktop / mobile).
import 'dart:io';
File('output.xlsx').writeAsBytesSync(excel.save()!);

// 3) Trigger a browser download on Flutter Web.
excel.save(fileName: 'report.xlsx');

Flutter — read from assets, edit, and save #

import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';

final data = await rootBundle.load('assets/template.xlsx');
final excel = Excel.decodeBytes(data.buffer.asUint8List());

excel['Sheet1'].updateCell(CellIndex.indexByString('A1'), TextCellValue('Updated'));

final dir = await getApplicationDocumentsDirectory();
File('${dir.path}/output.xlsx').writeAsBytesSync(excel.save()!);

excel_plus vs excel #

excel_plus is a performance-focused fork of the excel package that keeps the same public API.

excel_plus excel
XML parsing Streaming SAX (parseEvents) Full-DOM (standard)
Sheet loading Lazy, per sheet on first access Eager
Large-file memory Low — untouched parts reused byte-for-byte on save Higher
Public API Source-compatible drop-in — (the original)
Platforms VM, Web (JS & WASM), Android, iOS, desktop VM, Web, mobile

On a 1,000,000-cell sheet this measured ~5× faster encoding, ~3× faster decoding, and ~3.5× less peak memory — see Performance for the reproducible head-to-head.

Live pub score and likes are shown in the badges at the top.

Migrating from the excel package #

// Before
import 'package:excel/excel.dart';

// After
import 'package:excel_plus/excel_plus.dart';

No other code changes needed for typical usage — excel_plus mirrors the excel package's public API.

FAQ #

Is excel_plus a drop-in replacement for the excel package? Yes. The classes, methods, and enums match the excel package — change the import to package:excel_plus/excel_plus.dart and your existing code keeps working.

Which platforms are supported? Dart VM, Web (both JavaScript and WebAssembly), and mobile (Android & iOS) via Flutter, as well as desktop. It is a pure-Dart package with no dart:io in the public path.

Can it read and write large .xlsx files efficiently? Yes — sheets are parsed with a streaming SAX reader and loaded lazily, and untouched parts of the workbook are reused byte-for-byte on save, keeping memory low.

Does it support formulas, styling, and merged cells? Yes — formula cells, full cell styling (fonts, colors, fills, borders, alignment, number formats), and merging/unmerging with custom values are all supported.

Is it Flutter-only? No. excel_plus is a pure Dart library; it works in plain Dart and in Flutter apps alike.

Support and feedback #

  • Found a bug or want a feature? Open an issue on the issue tracker.
  • Questions and ideas are welcome via GitHub Discussions.
  • Pull requests are welcome — see the repository for contribution guidelines.

About #

excel_plus is an open-source, MIT-licensed, performance-focused fork of the excel package, rebuilt around a streaming parser and lazy loading for speed and low memory on large .xlsx files while staying API-compatible.

excel_plus is created and owned by Nurullah Al Masum.

Contributors #

excel_plus grows with its community — every contributor is listed here:

excel_plus contributors

Want to help? Pull requests are welcome — see Support and feedback.

If excel_plus helps you, please ⭐ the repository and 👍 it on pub.dev — it genuinely helps others find it.

37
likes
0
points
5.12k
downloads

Publisher

verified publisheralmasum.dev

Weekly Downloads

Fast, low-memory Excel (.xlsx) library for Dart and Flutter to read, create, edit, and style spreadsheets. A drop-in replacement for the excel package.

Repository (GitHub)
View/report issues

Topics

#excel #xlsx #spreadsheet #office #workbook

License

unknown (license)

Dependencies

archive, web, xml

More

Packages that depend on excel_plus