excel_plus 2.0.0
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 (.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
.xlsxfiles, 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.
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:
| 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 #
- Excel (.xlsx) Library for Dart & Flutter
- Overview
- Performance
- Table of contents
- Key features
- Limitations
- Roadmap
- Example
- Other useful links
- Installation
- Getting started
- Create a simple Excel document
- Add text, number, boolean, and date values
- Add formulas
- Read an existing Excel file
- Read a single cell
- Style a cell — font, color, fill, alignment
- Add borders
- Apply number formats
- Merge and unmerge cells
- Insert and delete rows and columns
- Append a row
- Column width, row height, and auto-fit
- Work with multiple sheets
- Find and replace
- Save the workbook
- Flutter — read from assets, edit, and save
- excel_plus vs excel
- Migrating from the excel package
- FAQ
- Support and feedback
- About
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 #
▶ Try the live demo — build, style and export real
.xlsxfiles 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.
Other useful links #
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:
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.