Objective, reproducible spreadsheet-library benchmarks with a Python-first decision surface.
Most Excel library comparisons focus on speed. ExcelBench focuses on the question developers actually have:
Can this library handle my real spreadsheet without breaking the parts I care about?
ExcelBench models 22 XLSX features across 14 Python adapters plus a cross-language context lane (Apache POI, Excelize, zavora-xlsx). Tier 4 (sheet protection, page setup, chart anchoring) was added in the 2026-09-08 competitor snapshot.
Competitor snapshot: 2026-10-02 | WolfXL 2.0.5 (latest PyPI) | 17 fidelity adapters incl. SheetJS CE 0.20.3, ExcelJS 4.4.0, LibreOffice 26.8.0.3 | Snapshot README | Fidelity | Mutation | Calc | Cross-language
Green features in that snapshot (read / write, out of 21ΒΉ): openpyxl 21/21 / 21/21, WolfXL 19/21 / 18/21, ExcelJS 12/21 / 15/21, aspose-cells-foss 11/21 / 14/21, LibreOffice 12/21 / 12/21, SheetJS CE 9/21 / 8/21; write-only xlsxwriter 15/21.
Mutation suite (two-cell edit on a corporate template, content-model preservation; features kept / features in the template): WolfXL Preserved 17/17; openpyxl 16/17 (drops custom XML); LibreOffice 15/17 (cell styles, page setup); aspose-cells-foss 15/17 (drops 87 string cells, custom XML); SheetJS 8/17 and zavora-xlsx 8/17 (charts, tables, styles and more); ExcelJS fails to load the template. Every engine that ran applied both edits. Wall times in that run are not comparable (host under heavy unrelated load).
Calc tier (133-formula financial DAG, cache-free fixture, LibreOffice oracle): LibreOffice 133/133, aspose-cells-foss 25/133, WolfXL 0/133, zavora 0/133. SheetJS CE, ExcelJS, and the other non-calculating adapters are not applicable.
Cross-language context (write lane): Apache POI 5.5.1 18/21, Excelize 2.10.1 18/21, zavora-xlsx 0.1.2 8/21. The POI and Excelize misses are the three Tier 4 features, which the ExcelBench adapters do not implement yet (
NotImplementedError). They are not library gaps.ΒΉ
pivot_tablesis excluded from every denominator because no adapter produced a score for it in either competitor snapshot.Python release snapshot: 2026-04-29 UTC | wheel-backed WolfXL 2.0 rerun | Fidelity | Perf | Dashboard
In that snapshot, WolfXL reaches
18/18green features with100%pass rate.Performance snapshot: 2026-10-02 UTC | WolfXL 2.0.5 through its public API (
wolfxl.load_workbook,wolfxl.Workbook) | Perf. It supersedes the 2026-04-29 perf numbers for WolfXL, which measured private backend objects.Cross-language context snapshot: Apache POI
18/18| Excelize18/18Pivot capability lane: separate artifact because the shipped macOS pivot fixture is not scoreable, while
excelizecan still emit pivot-bearing workbooks.Historical public baseline: 2026-02-17 | Excel 16.105.3 | macOS (Apple Silicon) | Full results
Newer performance snapshot: 2026-04-20 | Perf results
Read Public Reporting Status before quoting numbers across snapshots.
The current story: ExcelBench now has three useful lanes. The Python release lane answers the migration question. The cross-language lane answers the ecosystem-positioning question. The pivot capability lane captures pivot evidence separately when the scored fixture is not valid on this platform. Keep every claim tied to the exact dated artifact you are citing.
ExcelBench intentionally keeps the main public comparison Python-first. That is the decision surface most users care about: openpyxl, xlsxwriter, python-calamine, pandas, and adjacent Python options.
Cross-language libraries matter too, but for a different reason: they show how strong WolfXL looks next to mature spreadsheet tooling outside Python. The current checked-in cross-language lane includes:
Apache POIExcelizezavora-xlsx(Rust writer, added 2026-09-08)
Pivot tables sit in a separate capability lane. On macOS, the shipped pivot fixture does not currently contain scoreable pivot OOXML, so the pivot story is tracked as a dedicated artifact instead of being mixed into the scored lane.
See cross-language comparison strategy.
-
Python replacement lane Use this when the question is: what should a Python team use instead of
openpyxl? -
Cross-language context lane Use this when the question is: how does WolfXL compare to serious spreadsheet tooling in Java, Go, and Rust?
-
Pivot capability lane Use this when the question is: can the cross-language helpers detect or emit pivot-bearing workbooks even when the main scored fixture is not valid on macOS?
-
Template-mutation lane Use this when the question is: which engine can surgically edit a corporate template fastest while preserving everything else in the workbook?
-
Formula-recalculation lane Use this when the question is: which engine actually computes a 133-formula financial DAG from scratch (cache-free fixture, LibreOffice oracle)?
| Library | Caps | Fidelity | Read Speed | Write Speed | Modify |
|---|---|---|---|---|---|
| wolfxl | R+W | R 20/21, W 19/21 in 2026-09-08 competitor snapshot (18/18 in 2026-04-29 snapshot) | 1.69x (13.46 ms) | 1.20x (22.28 ms) | Patch (Preserved, 17/17 features in 2026-10-02 mutation suite) |
| openpyxl | R+W | R 21/21, W 21/21 in 2026-09-08 competitor snapshot | 1.00x (22.79 ms, baseline) | 1.00x (26.70 ms, baseline) | Rewrite (16/17 features in 2026-10-02 mutation suite) |
| aspose-cells-foss | R+W | R 11/21, W 14/21 in 2026-09-08 competitor snapshot | not measured | not measured | Rewrite (15/17 features) |
| xlsxwriter | W | 15/18 in 2026-04-29 release snapshot | -- | 0.86x (31.12 ms) | No |
| xlsxwriter-constmem | W | 12/18 in 2026-04-29 release snapshot | -- | 0.86x (31.17 ms) | No |
| python-calamine | R | 1/18 in 2026-04-29 release snapshot | 14.02x (1.63 ms) | -- | No |
| pandas | R+W | 3/18 in 2026-04-29 release snapshot | 0.80x (28.43 ms) | 1.00x (26.66 ms) | Rebuild |
| polars | R | 0/18 in 2026-04-29 release snapshot | 3.72x (6.13 ms) | -- | No |
Speed columns come from the 2026-10-02 perf snapshot: sum of per-feature p50 wall times over the same 19 xlsx features for every library (warmup 3, 25 iterations, Apple M4 Pro, Python 3.12.3), shown as openpyxl's total divided by the library's total. WolfXL 2.0.5 is measured through its public API (
wolfxl.load_workbook,wolfxl.Workbook), like every other library. aspose-cells-foss was not part of the perf run. Always cite the artifact date, workload, and profile. See METHODOLOGY.md and Public Reporting Status.
- High-fidelity libraries are rare: in the 2026-04-29 release snapshot, only openpyxl and WolfXL reached 18/18 green features; in the 2026-09-08 competitor snapshot (21 scored features;
pivot_tablesunscored), openpyxl holds 21/21 read and write while WolfXL 2.1.0 reaches 20/21 read and 19/21 write - WolfXL 2.1.0 regression signal: conditional-formatting read scores 0 and named-range / print-title writes score 2 in the 2026-09-08 snapshot; tracked for the WolfXL repo
- Patch modify is structurally different: WolfXL's
load_workbook(path, modify=True)uses surgical ZIP patching; it is the only engine whose output keeps every template feature in the 2026-10-02 mutation suite - The abstraction tax is real: pandas wraps openpyxl but drops from 16 to 3 green features due to DataFrame coercion (errors become NaN)
- Speed vs fidelity tradeoff is measurable: use the perf snapshot together with the fidelity matrix rather than quoting one without the other
- Optimization modes have clear costs: openpyxl-readonly loses 13 green features for streaming speed
- Cross-language context is now strong too:
Apache POIandExcelizeland at18/18in the scored write lane;zavora-xlsx0.1.2 writes fast but corrupts hyperlink relationships on mutate and cannot recalculate - Calculation is a differentiator: in the 2026-10-02 calc rerun, LibreOffice, WolfXL Community 2.0.7, and WolfXL Commercial 2.3.0 compute all 133 formulas; aspose-cells-foss covers 25/133 and zavora-xlsx 0/133. Community's
save()writes no calculated values (0/133 saved), while Commercial saves all 133
See the release snapshot dashboard for the fresh wheel-backed combined view, or the historical dashboard for the older public baseline.
| Score | Meaning |
|---|---|
| π’ 3 | Complete -- full fidelity, indistinguishable from Excel |
| π‘ 2 | Functional -- works for common cases, some edge-case failures |
| π 1 | Minimal -- basic recognition but significant limitations |
| π΄ 0 | Unsupported -- errors, corruption, or complete data loss |
| Library | Version | Lang | Caps | Green Features |
|---|---|---|---|---|
| WolfXL | 2.1.0 | Python (Rust core) | R+W | R 20/21, W 19/21 (2026-09-08 snapshot) |
| openpyxl | 3.1.5 | Python | R+W | R 21/21, W 21/21 (2026-09-08 snapshot) |
| aspose-cells-foss | 26.7 | Python (JVM-core FOSS) | R+W | R 11/21, W 14/21 (2026-09-08 snapshot) |
| XlsxWriter | 3.2.9 | Python | W | 15/18 |
| xlsxwriter-constmem | 3.2.9 | Python | W | 12/18 |
| openpyxl-readonly | 3.1.5 | Python | R | 3/18 |
| pandas | 3.0.0 | Python | R+W | 3/18 |
| pyexcel | 0.7.4 | Python | R+W | 3/18 |
| tablib | 3.9.0 | Python | R+W | 3/18 |
| pylightxl | 1.61 | Python | R+W | 2/18 |
| python-calamine | 0.6.1 | Rust | R | 1/18 |
| polars | 1.38.1 | Rust | R | 0/18 |
| xlwt | 1.3.0 | Python | W | 4/18 |
| xlrd | 2.0.2 | Python | R | .xls only |
Green-feature counts are per dated snapshot;
x/18numbers come from the 2026-04-29 release snapshot andx/21from the 2026-09-08 competitor snapshot (Tier 4 added;pivot_tablesis unscored and excluded from the denominator). Never mix counts across snapshots.
| Library | Version | Lang | Caps | Notes |
|---|---|---|---|---|
| Apache POI | 5.x | Java | W | 18/18 scored write lane (2026-04-29) |
| Excelize | 2.x | Go | W | 18/18 scored write lane (2026-04-29) |
| zavora-xlsx | 0.1.2 | Rust | W | Fast writer; 0.1.2 corrupts hyperlink relationships on mutate; no recalc |
| Library | Green Features | Notes |
|---|---|---|
| xlrd | 4/4 | Full .xls read fidelity |
| python-calamine | 2/4 | Cross-format reader |
Five additional adapters via Rust/PyO3 extension modules:
| Library | Caps | Source | Notes |
|---|---|---|---|
| WolfXL (calamine-styled) | R | PyPI | Full-fidelity Rust reader with style extraction |
| WolfXL (rust_xlsxwriter) | W | PyPI | Full-fidelity Rust writer |
| calamine (basic) | R | Local | Direct calamine bindings (data only, no styles) |
| rust_xlsxwriter (direct) | W | Local | Direct rust_xlsxwriter bindings |
| umya-spreadsheet | R+W | Local | Rust read + write |
# WolfXL adapters (from PyPI β no Rust toolchain needed)
uv sync --extra rust
# Local-only adapters (requires Rust toolchain + maturin)
uv run maturin develop --manifest-path rust/excelbench_rust/Cargo.toml \
--features calamine,rust_xlsxwriter,umya
uv syncmay uninstall locally-built extensions; rerunmaturin developafter.
ExcelBench now ships a separate cross-language context snapshot for mature non-Python spreadsheet libraries:
Apache POI(Java)Excelize(Go)zavora-xlsx(Rust writer, added 2026-09-08; helper intools/external-oracles/zavora)
These are not framed as Python drop-in replacements. They answer a different question: how strong is WolfXL relative to serious spreadsheet tooling outside Python?
Current checked-in cross-language snapshot:
results-cross-language/README.mdresults-cross-language/CONTEXT.mdresults-cross-language-pivots/README.mddocs/cross-language-context.md
Current takeaways from that snapshot:
apache-poi:18/18green features in the scored write surfaces of this laneexcelize:18/18green features in the scored write surfaces of this lanepivot_tables: tracked in a separate capability artifact because the shipped macOS fixture does not contain scoreable pivot OOXML, whileexcelizecan still emit pivot-bearing workbooks
The concrete rollout plan for the first two candidates is here:
Run the dedicated cross-language context snapshot with:
uv run excelbench cross-language-context --tests fixtures/excel --output results-cross-languageRun the dedicated pivot capability artifact with:
uv run excelbench cross-language-pivot-context --fixture fixtures/excel/tier2/15_pivot_tables.xlsx --output results-cross-language-pivots- Generate reference files -- xlwings drives real Excel to produce canonical
.xlsx/.xlstest files with known features. - Read tests -- each library reads the Excel-generated file; extracted values are compared to the expected manifest.
- Write tests -- each library writes a new file from the same spec; the output is verified by a trusted oracle (Excel via xlwings, or openpyxl in CI).
- Score -- pass rates map to the 0-3 fidelity scale per feature.
Full methodology: METHODOLOGY.md
- Treat each
results/directory as a dated snapshot. - Do not merge February fidelity claims and April perf claims into one undated headline.
- Cite the artifact date and workload whenever quoting a speedup number.
- Keep WolfXL-specific release claims aligned with the WolfXL repo's evidence page.
WolfXL documentation lives in the wolfxl repository.
# Install
uv sync
# Run the benchmark against pre-built fixtures (no Excel required)
uv run excelbench benchmark --tests fixtures/excel --output results
# Template-mutation suite (wall time, RSS, preservation)
uv run excelbench mutation
# Formula-recalculation tier (cache-free fixture, LibreOffice oracle)
uv run excelbench calc
# Generate the heatmap
uv run excelbench heatmap
# Generate the combined fidelity + performance dashboard
uv run excelbench dashboard
# View results
open results/xlsx/README.md # macOS; use xdg-open on LinuxTo regenerate canonical fixtures from scratch (requires Excel installed):
uv run excelbench generate --output fixtures/excel| Tier | Features | Count |
|---|---|---|
| Tier 0 -- Core | Cell values, formulas, multiple sheets | 3 |
| Tier 1 -- Formatting | Text formatting, background colors, number formats, alignment, borders, dimensions | 6 |
| Tier 2 -- Advanced | Merged cells, conditional formatting, data validation, hyperlinks, images, comments, freeze panes, pivot tables | 8 |
| Tier 3 -- Workbook metadata | Named ranges, tables | 2 |
| Tier 4 -- Production surfaces (2026-09-08) | Sheet protection, page setup, chart anchoring | 3 |
Pivot tables are tested but score N/A across all adapters in the current macOS run. Green-feature denominators: /18 in the 2026-04-29 release snapshot, /21 in the 2026-09-08 and 2026-10-02 competitor snapshots (22 features modeled;
pivot_tablesis unscored and excluded).
None currently queued. Tier 4 (charts anchoring, print settings, protection) shipped 2026-09-08.
- Competitor snapshot fidelity -- 22 features x 14 Python adapters, WolfXL 2.1.0 + aspose-cells-foss
- Competitor snapshot heatmap (SVG) -- 22x14 visual score matrix
- Competitor snapshot mutation -- template mutation: wall time, RSS, preservation
- Competitor snapshot calc -- 133-formula financial DAG vs LibreOffice oracle
- Competitor snapshot zavora cross-language -- zavora-xlsx 0.1.2 Rust writer context
- XLSX results -- per-library, per-test-case breakdowns with tier list
- Release snapshot results -- fresh wheel-backed WolfXL 2.0 rerun
- XLS results -- legacy format results
- Performance results -- 2026-04-20 perf snapshot (historical; its WolfXL column measured private backend objects)
- Release snapshot perf -- 2026-04-29 perf snapshot (historical; its WolfXL column measured private backend objects)
- 2026-10-02 perf snapshot -- current perf: 13 Python adapters, 19 features, WolfXL 2.0.5 through its public API
- Dashboard -- combined fidelity + performance comparison
- Release snapshot dashboard -- combined view for the fresh rerun
- Heatmap (PNG) | SVG -- visual score matrix
v0.1.0 -- actively maintained benchmarking harness with dated fidelity and performance snapshots, reproducible methodology, and multi-adapter coverage across Python and Rust-backed spreadsheet libraries.
See CONTRIBUTING.md for setup instructions, how to add features, and how to add library adapters.
MIT
