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.
The 30-second walkthrough
- Open freefileconverter.ai/xlsx-to-csv.
- Drag the
.xlsxonto the drop zone, or tap to pick it from your file picker. - 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. - Click the per-row download or hit Download all (ZIP) for a batch run.
- Pipe the CSV straight into
\copy,LOAD DATA INFILE, orpandas.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:
- LibreOffice headless is a 350MB install. For one file, it's the equivalent of buying a forklift to move a chair.
- csvkit needs a Python environment, a virtualenv, and remembering which one you set up two laptops ago. The actual conversion is one command; getting to the command takes longer than uploading-and-downloading would.
- openpyxl needs you to write four lines of Python. Worth it inside a pipeline, overkill for a one-off file from a contractor.
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:
- The actual work — decode OOXML, emit CSV — is the part the browser already does. The upload is the ad-rev event, not a technical requirement.
- Workbooks tend to contain things you don't want on someone else's server: payroll, customer lists, financial models, contract terms. The shape of an
.xlsxby file size alone often signals sensitivity. - Most of those tools don't disclose retention. The file you "deleted" via the UI is usually still in an S3 bucket somewhere on a 7-, 30-, or never-day cycle. Why "free" converters upload your files goes deeper on this pattern.
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:
- CSV to JSON — for APIs that accept JSON arrays, or for shoving rows into a NoSQL store. See also CSV to JSON in your browser: 3 use cases for non-developers.
- JSON to CSV — for the return trip, when an API response needs to land in a spreadsheet for a non-technical reviewer.
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 browserEdge cases worth knowing
- Workbooks with macros (
.xlsm). The converter reads the data tables fine but ignores macro code, which is correct — macros don't belong in a CSV. If you need to know what a macro did to a column, run it in Excel/LibreOffice first, then save as.xlsxand convert. - Encoding. Output is UTF-8. Postgres handles it with
ENCODING 'UTF8'; pandas withencoding='utf-8'. Non-Latin characters survive intact. - Delimiter. The output uses commas. Fields containing commas (addresses, sentence fragments) are quoted per RFC 4180. For pipe- or tab-separated output, post-process; SQL
COPYhandles arbitrary delimiters via theDELIMITERclause. - Old
.xlsbinary format. The pre-2007 binary.xlsformat is a different decoder. The tool handles simple.xlsfiles but the safer path is to open the file once and re-save as.xlsx.