mrkeyoor.com_
Sun 20 Sept 08:57 UTC
PyPIDataupdated 20 Sept 2026

xlsxwriter review

XlsxWriter 3.2.9 creates new Excel 2007+ .xlsx files from Python. It writes cells, formulas, formats, tables, charts, images, comments, validation rules, conditional formats, named ranges, macros, and print settings. pandas and Polars can select it as an output engine, then expose native workbook objects for final layout work. The defining limit is in the name: XlsxWriter cannot read or alter an existing workbook. Version 3.2.9 also removes py.typed because partial annotations were breaking downstream checks. Our install had no dependencies and imported in 0.27 seconds.

Verdict

XlsxWriter 3.2.9 installed in 0.2 seconds as 1 MB with 0 dependencies in our sandbox, but it can only create new XLSX files and has no py.typed marker. Install it for formatted reports built from scratch; install openpyxl when the first requirement is to open or edit a workbook.

We installed it

Lab card: what happened when we installed xlsxwriterScreenshot of xlsxwriter documentation
Install✓ · 0.2s1 package on disk · 1 MB
Importimport xlsxwriter in 0.27s · pure Python · requires Python >=3.8
Known vulns0(pip-audit)

Answers from our run

Does xlsxwriter install cleanly?

Yes. In a fresh container with an empty cache, pip install xlsxwriter finished in 0.2s, leaving 1 package and 1 MB on disk. pip-audit reported no known vulnerabilities.

What does xlsxwriter need to run?

Python >=3.8, and nothing compiled: it is pure Python. In our run import xlsxwriter succeeded in 0.27s.

xlsxwriter or openpyxl: which should you use?

openpyxl: Use it when Python 3 code must read, edit, or fill an existing XLSX workbook. XlsxWriter 3.2.9 installed in 0.2 seconds as 1 MB with 0 dependencies in our sandbox, but it can only create new XLSX files and has no py.typed marker.

When should you not use xlsxwriter?

An existing workbook or template must be opened and edited; XlsxWriter has no read API, so use openpyxl

API stability5/5Workbook, Worksheet, Format, and Chart retain the same procedural structure throughout the 3.x line, and recent spreadsheet features arrive as new methods or options. Version 3.2.9 changes static-analysis discovery by removing py.typed, which can fail typed-package policy even though runtime calls stay unchanged. The release notes explain that the marker will return after annotation coverage improves rather than pretending the current types are complete.
Docs5/5The documentation has focused chapters for workbook creation, cells, formats, charts, formulas, images, memory use, macros, pandas, Polars, and known Excel limitations. The example gallery pairs generated workbooks with source code, and method pages usually state hard limits such as worksheet naming, validation length, or constant-memory restrictions. That specificity makes it possible to design an export before discovering an Excel constraint at close time.
Maintenance4/5PyPI published version 3.2.9 on 2025-09-16, GitHub records a later push on 2026-08-04, and 28 open items combine issues with pull requests. The repository is active and unarchived, while its scope has stayed focused on writing XLSX files. Development is still centered on one main author, so organizations depending on an unusual Excel edge should keep a representative workbook in regression tests.
Ecosystem5/5PyPI Stats counted 23,666,694 downloads in the latest week and GitHub reported 3,967 stars. pandas and Polars both integrate XlsxWriter as an Excel output engine and expose its native workbook objects for formatting. The package handles common business-report features directly, including charts, tables, validation, images, macros, and print layout, while our install added 0 dependency packages.

Use it if

  • A Python 3.8+ job must produce a new XLSX report with formulas, charts, formats, filters, or validation
  • A pandas or Polars export needs workbook-level formatting after tabular values are written
  • Deployment wants a pure-Python writer with 0 runtime dependencies and no compiler step
  • A large row-ordered export can accept constant_memory restrictions to keep row storage bounded
Skip it if

Setup reality

We installed XlsxWriter 3.2.9 in 0.2 seconds with Python 3.12. It left 1 package and 1 MB on disk, declared 0 direct dependencies, and pip-audit found 0 known vulnerabilities. import xlsxwriter finished in 0.27 seconds. The distribution is pure Python, requires Python 3.8+, uses BSD-2-Clause, and does not ship py.typed. The How we test run used a fresh unprivileged container with no package cache.

There are no credentials or global config files. Workbook() creates a new target, and close() assembles the final ZIP-based XLSX file. Use a with block where possible and still handle exceptions because invalid worksheet names, duplicate names, filesystem errors, and ZIP limits can appear during finalization. Since XlsxWriter cannot reopen its result, important exports need an acceptance check in Excel or a second library that can read the generated workbook.

Excel stores dates as serial numbers. write_datetime() needs an appropriate number format or users see that raw value. XLSX cells do not preserve Python time-zone objects, so normalize to an agreed zone before dropping tzinfo. Formats are shared workbook records: create a small palette once and do not mutate a Format after earlier cells reference it. Formulas are written without evaluation; pass a cached value for readers that never recalculate.

constant_memory flushes completed rows and therefore requires increasing row indexes. A later write to an earlier row cannot behave like normal mode, while add_table() and autofit() are unavailable. Images, charts, and formula strings can still make a 1 MB Python install generate a very large file. For DataFrames, enter through pandas.ExcelWriter or Polars, access writer.book and writer.sheets for formatting, then finish all workbook calls before the surrounding context closes.

Patterns

Write a new XLSX file create-workbook

import xlsxwriter

with xlsxwriter.Workbook('report.xlsx') as workbook:
    sheet = workbook.add_worksheet('Summary')
    sheet.write('A1', 'Region')
    sheet.write('B1', 'Revenue')
    sheet.write(1, 0, 'EMEA')
    sheet.write(1, 1, 120400)

The context finalizes the ZIP container on exit. Row and column numeric indexes start at 0.

Build a small workbook format palette reuse-cell-formats

formats = {
    'header': workbook.add_format({'bold': True, 'bg_color': '#DDEBF7', 'border': 1}),
    'money': workbook.add_format({'num_format': '#,##0.00'}),
    'date': workbook.add_format({'num_format': 'yyyy-mm-dd'}),
}
sheet.write('A1', 'Revenue', formats['header'])
sheet.write('A2', 1204.5, formats['money'])

Each Format belongs to 1 workbook. Reuse a limited palette instead of creating near-identical records inside a row loop.

Append rows in order write-record-rows

headers = ['Region', 'Revenue', 'Margin']
rows = [('EMEA', 120400, 0.184), ('APAC', 98100, 0.211)]
sheet.write_row(0, 0, headers, formats['header'])
for row_index, values in enumerate(rows, start=1):
    sheet.write_row(row_index, 0, values)

write_row applies 1 optional format to all values. Use cell writes when columns need different number formats.

Store a visible date value write-excel-date

from datetime import datetime

sheet.write_datetime('A2', datetime(2026, 8, 26, 14, 30), formats['date'])

Excel stores this as a number. Normalize time zones first because XLSX cells do not preserve Python tzinfo.

Supply a formula result for simple readers cache-formula-result

sheet.write_formula('D2', '=B2*C2', formats['money'], 22153.6)

XlsxWriter does not calculate formulas. The fourth value is a cached result for software that does not recalculate the workbook.

Create a status dropdown add-validation-list

sheet.data_validation('E2:E500', {
    'validate': 'list',
    'source': ['Open', 'In progress', 'Closed'],
    'input_title': 'Status',
    'error_message': 'Choose a listed value.',
})

Excel limits inline validation sources to 255 characters. Put longer choices on a hidden sheet and reference that range.

Keep row memory bounded stream-large-sheet

workbook = xlsxwriter.Workbook('big.xlsx', {'constant_memory': True})
sheet = workbook.add_worksheet()
for row_index, values in enumerate(stream_records()):
    sheet.write_row(row_index, 0, values)
workbook.close()

Write rows in increasing order. In constant_memory mode, add_table() and autofit() warn and do nothing.

Adjust a DataFrame worksheet format-pandas-export

import pandas as pd

with pd.ExcelWriter('out.xlsx', engine='xlsxwriter', datetime_format='yyyy-mm-dd') as writer:
    df.to_excel(writer, sheet_name='Data', index=False)
    sheet = writer.sheets['Data']
    sheet.set_column('A:A', 24)
    sheet.freeze_panes(1, 0)
    sheet.autofilter(0, 0, len(df), len(df.columns) - 1)

writer.book and writer.sheets expose XlsxWriter objects only before the pandas context closes the file.

Chart worksheet data insert-column-chart

chart = workbook.add_chart({'type': 'column'})
chart.add_series({
    'name': 'Revenue',
    'categories': ['Summary', 1, 0, 12, 0],
    'values': ['Summary', 1, 1, 12, 1],
})
chart.set_title({'name': 'Revenue by region'})
sheet.insert_chart('E2', chart)

The chart references worksheet coordinates, so its 12 source rows must exist even if their sheet is later hidden.

Alternatives

PackageRegistryPick it when
openpyxlPyPIUse it when Python 3 code must read, edit, or fill an existing XLSX workbook
pandasPyPIUse DataFrame.to_excel when table export matters more than detailed workbook construction
pyexceleratePyPIUse it for large rectangular writes where cell throughput matters more than workbook features

More data guides

numpy · fsspec · pandas · sqlalchemy · pyarrow · lxml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.