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 files from bytes.
  • Create new Excel workbooks from scratch.
  • Multiple sheets — create, copy, rename, delete, reorder, tab colour, hide.
  • All cell types — text, int, double, bool, date, time, date-time, formula, and typed error values (#DIV/0!, #N/A, …).
  • Cell styling — fonts, colors, solid & pattern fills, borders, alignment, rotation, indent.
  • Number formats — built-in and custom format codes.
  • Worksheet features — hyperlinks, data validation / dropdowns, conditional formatting (colour scales, data bars, cellIs/formula), freeze panes, autofilter, sheet & workbook protection, defined names / named ranges, gridlines & zoom.
  • Images — insert PNG/JPEG/GIF anchored to a cell (sheet.insertImage) and read them back (sheet.images); existing pictures are preserved on save.
  • Page & print setup — orientation, scaling / fit-to-page, margins, print area, repeating print titles, and manual page breaks (sheet.pageSetup, sheet.setPrintArea, sheet.setPrintTitleRows, sheet.insertRowPageBreak, …).
  • Grouping & outline — collapsible row/column groups with outline levels, plus show/hide (sheet.groupRows, sheet.groupColumns, sheet.setRowHidden).
  • Comments / notes — attach and read classic cell comments with author (sheet.setComment, cell.comment, sheet.comments).
  • Rich text — read and write (per-run bold/italic/colour/size/font).
  • Theme & indexed colours — read (resolved to RGB) and authored (ExcelColor.theme(ThemeColor.accent1, tint: x) / ExcelColor.indexed(n)), staying linked to the document theme.
  • Merge & unmerge cells with custom values.
  • Rows & columns — insert, remove, clear, resize.
  • Column width / row height with auto-fit.
  • Find and replace across cells and sheets.
  • Cross-platform — VM, Web (JS & WASM), Android, iOS, Windows, macOS, Linux.
  • Source-compatible drop-in for the excel package.

Limitations

excel_plus focuses on fast, correct cell data and styling I/O. The following are not supported yet — if you need one, please open an issue so it can be prioritised:

  • Formula evaluation — formula cells round-trip with their cached result; Excel recomputes when the file is opened. excel_plus stores and preserves formulas but does not evaluate them itself.
  • Objects & media — charts and pivot tables (images and comments are supported; see Key features).
  • Split panes — freeze panes are supported; twip-based split panes are not.

Anything not in this list — reading, creating, editing and styling cells across multiple sheets — is supported; see Key features.

Roadmap

excel_plus is actively developed toward broader Excel / Google-Sheets parity. 1.0.0 landed the high-impact worksheet feature set (hyperlinks, data validation, conditional formatting, freeze panes, autofilter, sheet protection, named ranges, rich-text write, error values, theme/indexed colour authoring). 1.1.0 adds images, page & print setup, row/column grouping, cell comments, workbook protection, and pattern fills. Next up (subject to change): a formula-evaluation engine. Shipped changes are tracked in the changelog, and the direction is driven by what users request on the issue tracker.

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; Excel (or Sheets/Calc) computes the result when the file is opened — excel_plus does not evaluate them itself.

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)');

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.

Libraries

excel_plus
A high-performance library for reading, creating, and editing Excel .xlsx files in Dart and Flutter.