RustPy-XlsxWriter

June 7, 2026 · View on GitHub

PyPI version Python Versions License: MIT Downloads CI Docs Donate

High-performance Excel and CSV file generation for Python, powered by Rust. ~7x-9x faster than XlsxWriter, ~5x faster CSV (records) than Python's csv module, and ~12x faster Pandas DataFrame → CSV than pandas.to_csv via zero-copy Arrow.

from rustpy_xlsxwriter import FastExcel

FastExcel("report.xlsx").sheet("Sheet1", records).save()

Installation

pip install rustpy-xlsxwriter

Performance

Benchmarked via benchmark.py — run python benchmark.py to reproduce:

OutputInput typeRecordsRustPyBaselineSpeedup
ExcelRecords (list of dicts)500K~2.99s~26.72s8.9x
1M~5.94s~51.92s8.7x
Pandas DataFrame500K~1.21s~9.11s7.6x
1M~2.41s~18.17s7.5x
Polars DataFrame500K~1.20s~8.59s7.1x
1M~2.42s~17.07s7.1x
CSVRecords (generator)500K~0.16s~0.77s4.8x
1M~0.32s~1.53s4.8x
Pandas DataFrame1M~12x
Polars DataFrame1M(use Polars' native write_csv — already faster)†

Baselines: Excel → Python xlsxwriter; Records CSV → Python csv module; Pandas DataFrame CSV → DataFrame.to_csv().

DataFrame → CSV rows measured on a separate machine — only speedup ratio shown. The Pandas path goes through zero-copy Arrow C Data Interface.

Key optimizations
  1. Arrow zero-copy for DataFrames — reads memory buffers directly via Arrow C Data Interface (Excel and CSV paths)
  2. First-row type caching for Records — detect column types once, skip type cascade
  3. LTO (Link-Time Optimization) and single codegen unit
  4. Constant memory mode for large files
  5. Pre-allocated Format objects (created once, reused across all cells)
  6. Dict values() iteration instead of per-key hash lookups
  7. Lazy processing of Python iterables (including generators)
  8. High-precision floating point with ryu
  9. Efficient zlib compression

Features

Data Sources

  • List of dicts, generators/iterators, Pandas DataFrame, Polars DataFrame
  • All Python types: str, int, float, bool, None, datetime, date
  • Numpy scalar types (numpy.int64, numpy.float64, numpy.bool_)

Formatting & Styling

  • Float number format (e.g. "0.00")
  • Custom datetime format (e.g. "dd/mm/yyyy")
  • Bold headers and bold index columns
  • Freeze panes (rows, columns, per-sheet overrides)

Output Options

  • .xlsx (Excel) — auto-detected from file extension
  • .csv / .tsv — auto-detected; ~5x faster than Python csv (records), ~12x faster than pandas.to_csv (Pandas DataFrame, via Arrow zero-copy)
  • io.BytesIO in-memory buffer
  • Password protection (Excel only)
  • Optional column auto-fit (autofit=True/False)
  • Multiple sheets in a single file (Excel only)

API

  • Fluent builder via FastExcel class
  • Context manager (with statement) for auto-save
  • Lower-level functional API (write_worksheet, write_worksheets)

Quick Start

from rustpy_xlsxwriter import FastExcel

# Simple
FastExcel("output.xlsx").sheet("Users", [{"Name": "Alice", "Age": 30}]).save()

# Full-featured with context manager
with FastExcel("report.xlsx", password="secret") as f:
    f.format(
        float_format="0.00",
        datetime_format="dd/mm/yyyy",
        bold_headers=True,
        index_columns=["ID"],
    )
    f.freeze(row=1)
    f.sheet("Employees", employee_records)
    f.sheet("Departments", dept_records)

Usage Examples

Pandas & Polars DataFrames

import pandas as pd
import polars as pl
from rustpy_xlsxwriter import FastExcel

# Pandas — Arrow zero-copy, dtype-aware
df_pd = pd.DataFrame({"Name": ["Alice", "Bob"], "Score": [88.5, 92.3]})
FastExcel("pandas.xlsx").sheet("Data", df_pd).save()

# Polars — native support, no .to_pandas() needed
df_pl = pl.DataFrame({"Name": ["Alice", "Bob"], "Score": [88.5, 92.3]})
FastExcel("polars.xlsx").sheet("Data", df_pl).save()

Freeze Panes

# Freeze header row on all sheets
FastExcel("frozen.xlsx").freeze(row=1).sheet("Sheet1", data).save()

# Per-sheet freeze configuration
(
    FastExcel("custom.xlsx")
    .freeze(row=1)                             # all sheets
    .freeze(row=1, col=2, sheet="Details")     # override for Details
    .sheet("Summary", summary_data)
    .sheet("Details", detail_data)
    .save()
)

Column widths

Override autofit with explicit widths (Excel character units):

from rustpy_xlsxwriter import FastExcel

(
    FastExcel("out.xlsx")
    .sheet("RawData", rows, column_width=15)                    # uniform
    .sheet("Meta", meta, column_widths={"row": 7, "var": 22})   # per-column (by name)
    .sheet("Other", rows, column_widths=[7, 22, 40])            # per-column (positional)
    .save()
)

column_widths overrides column_width per named/positional column, and explicit widths win over autofit=True. Unknown column names and out-of-range list indices emit a warning and are skipped. For write_worksheets, pass column_width / column_widths as dicts keyed by sheet name (with a "general" fallback key).

Cell formatting

Build a reusable Format and attach it per column or to the header row:

from rustpy_xlsxwriter import FastExcel, Format

money = Format().set_num_format("$#,##0.00").set_font_color("#006600")
header = Format().set_bold().set_background_color("#1F4E78").set_font_color("white")

(
    FastExcel("out.xlsx")
    .sheet("Products", rows, header_format=header, column_formats={"price": money})
    .save()
)

Format chains setters (font, fill, border, alignment, number format). Colors accept "#RRGGBB" or names ("red"); enum-valued setters take lowercase strings (set_align("center"), set_border("thin")). A column's format wins over float_format / datetime_format. For write_worksheets, pass column_formats / header_format as dicts keyed by sheet name (with a "general" fallback key).

Note: a column format wins entirely over the automatic number format. On a date/datetime column, a Format without set_num_format(...) makes cells show the raw Excel serial number — chain .set_num_format("yyyy-mm-dd") (or similar) to keep a date display.

Generator Streaming

def rows():
    for i in range(1_000_000):
        yield {"id": i, "value": f"row_{i}"}

FastExcel("streamed.xlsx").sheet("Data", rows()).save()

In-Memory Buffer (Web Frameworks)

import io
from rustpy_xlsxwriter import FastExcel

buf = io.BytesIO()
FastExcel(buf).sheet("Sheet1", records).save()
xlsx_bytes = buf.getvalue()  # send as HTTP response

CSV / TSV Output

# Auto-detected from file extension — same API, no code change
FastExcel("output.csv").sheet("Sheet1", records).save()
FastExcel("output.tsv").sheet("Sheet1", records).save()

# Or use write_csv directly
from rustpy_xlsxwriter import write_csv

write_csv(records, "output.csv")
write_csv(records, "output.csv", delimiter=";")  # custom delimiter

Functional API

from rustpy_xlsxwriter import write_worksheet, write_worksheets

write_worksheet(records, "output.xlsx", sheet_name="Sheet1", password="secret")

write_worksheets(
    [("Sheet1", records1), ("Sheet2", records2)],
    "output.xlsx",
    freeze_panes={"general": {"row": 1, "col": 0}},
)

API Reference

FastExcel Class

MethodDescription
FastExcel(target, *, password=None, autofit=True)Create writer for file path or BytesIO buffer
.format(*, float_format, datetime_format, index_columns, bold_headers)Set number/datetime format and styling
.freeze(*, row=None, col=None, sheet=None)Configure freeze panes (general or per-sheet)
.sheet(name, data)Add a worksheet (list of dicts, generator, or DataFrame)
.save()Write all sheets and save

Supports context manager (with statement) — auto-saves on exit, skips save on exception.

Functional API

FunctionDescription
write_worksheet(records, file_name, ...)Write single Excel sheet
write_worksheets(records_with_sheet_name, file_name, ...)Write multiple Excel sheets
write_csv(records, file_name, delimiter=",")Write CSV/TSV file
validate_sheet_name(name)Check if sheet name is valid for Excel

Supported Data Types

Python TypeExcel Output
strText
intNumber
floatNumber (with optional format)
boolBoolean
NoneEmpty cell
datetime.datetimeDateTime (with optional format)
datetime.dateDate (with optional format)
numpy.int64 / numpy.float64Number
numpy.bool_Boolean
dict, otherString representation

Examples

See examples/ for 16 runnable scripts + a Jupyter notebook:

FileDescription
01_basic.pySingle sheet from list of dicts
02_multiple_sheets.pyMultiple sheets in one file
03_dataframe.pyPandas DataFrame with styling
04_freeze_panes.pyFreeze rows, columns, per-sheet config
05_bytesio.pyIn-memory buffer for web frameworks
06_generator.pyMemory-efficient streaming (100K rows)
07_password.pyPassword-protected workbook
08_full_featured.pyAll features combined
09_polars.pyPolars DataFrame (native support)
10_context_manager.pyAuto-save with with statement
11_datetime_format.pyCustom datetime/date formatting
12_bold_headers.pyBold header row
13_autofit.pyColumn auto-fit toggle
14_csv_tsv.pyCSV/TSV output (~5x faster)
15_column_widths.pyUniform & per-column widths
16_cell_formats.pyCell formatting (Format class)
quickstart.ipynbJupyter notebook walkthrough

Testing

# Unit tests (~1 second)
pytest tests/ -m "not benchmark"

# All tests including benchmarks
pytest tests/

# Benchmark only
python benchmark.py
Test structure (86 tests)
FileCoverage
test_metadata.pyPackage metadata functions
test_validation.pySheet name validation (unicode, length, special chars)
test_write_single.pySingle sheet: all types, generator, context manager, autofit
test_write_multi.pyMultiple sheets
test_write_functional.pyFunctional API
test_freeze_panes.pyFreeze panes (single & multi-sheet)
test_password.pyPassword protection
test_bytesio.pyIn-memory buffer I/O
test_dataframe.pyPandas DataFrame, numpy scalar types
test_polars.pyPolars DataFrame: types, datetime, date, null, styling
test_styling.pyFloat format, datetime format, bold headers, index columns
test_benchmark.pyPerformance benchmarks (Records + Pandas + Polars vs xlsxwriter)

Contributing

Contributions are welcome! Please submit issues or pull requests on the GitHub repository.

Support

If this project saves you time, consider supporting its development via Saweria ☕ — or use the Sponsor button at the top of the repository.

License

This project is licensed under the MIT License.

Acknowledgements

This project is powered by rust_xlsxwriter, PyO3, and maturin.