wolfsuite

Comparison receipts

openpyxl alternatives, measured side by side

Every number on this page comes from one committed benchmark run of the pinned public packages on 2026-08-18, median of 5 rounds, with the raw results file and the harness published in the open-source repository. Reproduce it before you rely on it.

Choose by job, not by benchmark chart

  • Modify an existing workbook (edit two cells in a template, keep everything else intact): only the full read/write libraries can do this at all. In this set that means WolfXL or openpyxl; XlsxWriter, PyExcelerate, python-calamine, and fastexcel structurally cannot modify an existing file.
  • Generate a new workbook from data: every library here except the read-only pair applies; the timing receipts below separate them.
  • Extract values out of .xlsx into Python: the read receipts below cover the read-only accelerators alongside the full engines.
  • Feed a pandas, Polars, or SQL pipeline: pandas, Polars, and DuckDB wrap several of these engines and are timed separately in the published results. They move DataFrames, not workbooks: cell styles, formulas, and template structure are outside their contract.

What each library can actually do

Capability scope of the pinned packages
LibraryRead .xlsxWrite .xlsxModify existing fileopenpyxl-shaped API
wolfxl 2.0.1full read/writeYesYesYesYes (drop-in alias)
openpyxl 3.1.5full read/writeYesYesYesIt is openpyxl
XlsxWriter 3.2.9write-onlyNoYesNoNo
PyExcelerate 0.13.0write-onlyNoYesNoNo
python-calamine 0.8.2read-onlyYes (values)NoNoNo
fastexcel 0.20.2read-onlyYes (Arrow)NoNoNo

The measured numbers, one committed run

AMD EPYC 9655, Python 3.13.15, median of 5 rounds per case. The large cases are a 200,000-row, 8-column sheet (1.6 million cells); the read fixture was written by openpyxl so no reader parses its own writer's output. Peak RSS comes from a separate pass that runs each case once per engine in a fresh process. Full tables, including mixed-type writes and DataFrame engines, are in the published results file (raw JSON, harness source).

Large-file receipts, 200,000 rows x 8 columns (1.6M cells), median of 5 rounds
LibraryRead 1.6M cellsWrite 1.6M cellsPeak RSS, writePeak RSS, read
wolfxl 2.0.1full read/write0.3868 s0.7258 s610 MiB153 MiB
openpyxl 3.1.5full read/write4.5856 s8.0567 s743 MiB169 MiB
XlsxWriter 3.2.9write-onlynot supported4.6858 s430 MiBnot supported
PyExcelerate 0.13.0write-onlynot supported3.6387 s264 MiBnot supported
python-calamine 0.8.2read-only0.5771 snot supportednot supported286 MiB
fastexcel 0.20.2read-only0.4030 snot supportednot supported267 MiB

On the 1.6-million-cell workbook, WolfXL wrote in 0.73 s (11.10x openpyxl, 6.46x XlsxWriter, 5.01x PyExcelerate) and read every value back in 0.39 s (11.85x openpyxl, 1.49x python-calamine, 1.04x fastexcel).

String-heavy write, 100,000 rows x 5 columns of unique strings (500K cells), median of 5 rounds
LibraryWrite 500K unique strings
wolfxl 2.0.1full read/write0.3091 s
openpyxl 3.1.5full read/write3.1452 s
XlsxWriter 3.2.9write-only2.1100 s
PyExcelerate 0.13.0write-only1.3407 s

String-heavy output is where real reports spend their time: WolfXL wrote 500,000 unique strings in 0.31 s, 10.18x openpyxl and 6.83x XlsxWriter.

Where the alternatives win or tie

  • Write peak memory: the write-only engines hold less memory while generating a file (XlsxWriter 430 MiB, PyExcelerate 264 MiB, WolfXL 610 MiB on the 1.6M-cell case) because they never keep a workbook model around for re-editing. That is the same design decision that makes them unable to read or modify anything.
  • Pure value extraction: fastexcel (0.4030 s) ties WolfXL (0.3868 s) on the 1.6M-cell read and returns Arrow tables directly, which suits DataFrame-first pipelines that never touch workbook structure.
  • Float precision: PyExcelerate, tablib, and pyexcel serialize floats with fewer significant digits than the other writers (a value like 8/7 does not round-trip bit-exactly), so their write numbers carry a precision tradeoff.
  • Pure-Python portability: pylightxl installs anywhere Python runs but took 241.09 s on the 1.6M-cell write (332x WolfXL); it fits small files, not this scale.
  • Small workbooks: below roughly 10,000 cells every library here is sub-second; the differences that matter show up at scale or on the modify path.

Switch from openpyxl

WolfXL Community follows the openpyxl-shaped API, so the switch is an install and an import change:

pip install wolfxl
# then
import wolfxl as openpyxl

Reproduce every number

The harness is public and deterministic about scope: write-only libraries run only write cases, read-only libraries only read cases, and engines that exceed the per-round budget are recorded as DNF rather than dropped.

git clone https://github.com/SynthGL/wolfxl-community
cd wolfxl-community
python -m venv .bench && .bench/bin/pip install wolfxl==2.0.1 openpyxl==3.1.5 \
    xlsxwriter pyexcelerate python-calamine fastexcel pyarrow pylightxl pandas \
    polars duckdb tablib pyexcel pyexcel-xlsx xlsx2csv
.bench/bin/python benchmarks/benchmark_python_excel_ecosystem.py \
    --rounds 5 --output-dir /tmp/ecosystem-results --prefix my-run

Numbers are from the pinned versions, hardware, and OS recorded in the results JSON. Different machines will produce different absolute times.