Article · XLSX · CSV · Postgres · MySQL · pandas

XLSX to CSV Without Excel or Google Sheets

Published June 12, 2026 · ~5 min read

Someone emailed you a .xlsx. Your import script wants .csv. The closest copy of Excel is a $69.99/year Microsoft 365 family plan or a corporate machine you don't feel like booting, and "just upload it to Google Sheets" means putting a client's financials into someone else's drive. There is a faster path, and it doesn't involve installing anything.

An .xlsx file is, structurally, a ZIP of XML files following the Office Open XML spec. The decoder runs perfectly fine in a browser tab. No license, no account, no upload — the bytes never leave the device.

Open the XLSX to CSV converter

The 30-second walkthrough

  1. Open freefileconverter.ai/xlsx-to-csv.
  2. Drag the .xlsx onto the drop zone, or tap to pick it from your file picker.
  3. If the workbook has one sheet, the output is a single .csv. If it has multiple sheets, the output is a ZIP containing one CSV per sheet, named after the sheet tab.
  4. Click the per-row download or hit Download all (ZIP) for a batch run.
  5. Pipe the CSV straight into \copy, LOAD DATA INFILE, or pandas.read_csv — whatever your destination expects.

The offline-pill at the bottom of the page stays lit through the whole conversion. The file is decoded with SheetJS in WebAssembly inside the page. We didn't build a server endpoint for this because there isn't a server step.

Why multi-sheet workbooks are the actual trap

Most "online Excel to CSV" tools quietly convert only the first sheet and call it done. That's fine for a one-tab pricing list, but the moment someone sends you a workbook called Q2-financials.xlsx with tabs for Revenue, COGS, Payroll, Summary, you end up with one CSV and three missing tables — and you don't notice until the import is two queries deep.

The converter on this site handles that case explicitly: every sheet becomes its own CSV inside the output ZIP, named exactly as the tab is named in Excel. Revenue.csv, COGS.csv, Payroll.csv, Summary.csv. Then you can pick the one you actually want, or shove all four into different tables in one Postgres session:

\copy revenue FROM 'Revenue.csv' DELIMITER ',' CSV HEADER;
\copy cogs    FROM 'COGS.csv'    DELIMITER ',' CSV HEADER;
\copy payroll FROM 'Payroll.csv' DELIMITER ',' CSV HEADER;
\copy summary FROM 'Summary.csv' DELIMITER ',' CSV HEADER;

The four things that break when you skip Excel

Excel quietly does a lot of "helpful" things when it exports CSV. Skipping it means understanding what you're giving up, so the import doesn't surprise you on the other side.

1. Formulas resolve to values, not strings

If the workbook has cells like =SUM(A2:A99), the CSV gets the computed number, not the formula text. That's almost always what you want for a data import. The one case where it isn't: if the formula references an external workbook or a live data source, the cached value is whatever Excel last saw — could be stale by months. Open the file in any spreadsheet tool first if you suspect that.

2. Dates come out in the workbook's stored format

Excel stores dates as serial numbers (days since 1900-01-01, except 1900 is incorrectly treated as a leap year — a Lotus 1-2-3 compatibility quirk). The CSV exporter resolves them to human-readable strings based on the cell's display format. If the column was formatted as m/d/yyyy, you'll get 6/12/2026 in the CSV. If it was formatted as yyyy-mm-dd, you'll get 2026-06-12. Postgres' DATE parser is happy with ISO format and sometimes finicky with US-style slashes — check the column format in Excel before you blame the converter.

3. Merged cells unmerge to the top-left value, blanks elsewhere

If row 7 has cells B7:D7 merged with the value "Q1 Total", the CSV gets "Q1 Total" in column B and empty strings in C and D. That's the spec-correct behavior — merged cells in OOXML are a presentation concern, not a data one. If you need the value repeated across the unmerged columns, that's a forward-fill in pandas (df.ffill(axis=1)) or a CASE in SQL.

4. Numbers stored as text stay text

If a column is full of values like '00123 (leading apostrophe to force text storage — common for zip codes and account numbers), the CSV preserves them as strings without the apostrophe. Postgres needs a TEXT or VARCHAR column, not INTEGER, or the leading zeros vanish on cast.

Where this beats LibreOffice, csvkit, and the rest

There are command-line options — libreoffice --headless --convert-to csv file.xlsx works, in2csv from csvkit works, even Python's openpyxl works. They're all fine. The friction is what they cost in setup time:

For a one-shot conversion, opening a page in the browser is faster than any of those, and it's still local-only. For a daily pipeline, write the openpyxl glue.

Why the upload-based "free" tools are worse than they look

The first page of Google for "xlsx to csv online" is dominated by sites that take the upload, run the same SheetJS conversion you can run locally, and hand you back the CSV behind a popup or a "preparing your download" spinner that exists to serve ads. Three things to notice:

If the file is a public dataset published on a government portal, none of this matters. If it's anything internal, it does.

Useful next steps after the CSV is in your hand

CSV is rarely the final destination — it's a transit format on the way to a database row, a pandas frame, a chart, or a Python script. Two adjacencies worth keeping bookmarked:

If the source file is a PDF report instead of a workbook, the right entry point is PDF to text rather than this tool — see extracting text from a PDF without uploading.

Convert XLSX to CSV in your browser

Edge cases worth knowing

Frequently asked questions

Does this work for password-protected workbooks?

No. A password-protected .xlsx is encrypted at the ZIP level — the decoder can read the structure but not the cell values without the password. Open it once in Excel/LibreOffice with the password, save an unprotected copy, then convert.

What happens to charts and pivot tables?

Charts are dropped — they're a visualization layer, not data. The underlying data range that feeds the chart is in the sheet and is in the CSV. Pivot tables are dropped from the output, but the source range that the pivot summarizes is in its own sheet (usually) and is preserved.

Will leading zeros (like zip codes) survive the conversion?

Only if the cell was stored as text in the workbook. Numeric cells with custom display formats that show leading zeros (e.g. zip codes formatted as 00000) lose the leading zeros in CSV — the underlying value was always an integer. To preserve them, change the column type to Text in the source workbook first, or import to a TEXT/VARCHAR column and zero-pad in SQL.

Can I pick which sheet to export when a workbook has many?

You get all of them as separate CSVs in a ZIP, named after the tabs. Pick the one you want from the unzipped folder; ignore the rest. There's no per-sheet selector in the UI today — the assumption is that selecting later is cheaper than asking before you know what's in the file.

Is the file uploaded anywhere?

No. Every byte of conversion happens inside the browser tab. The offline-pill at the bottom of the page is a live indicator — it stays lit through the conversion because the page genuinely doesn't need the network to do its job.

Related reading

Related tools

Files stay on your device. No login. Installs as a PWA on iPhone, Android, and desktop.
← Back to the blog · Free File Converter home