Excel to Parquet Converter
Turn a spreadsheet into something a data stack can read. Real column types, real compression, and a file pandas, Polars, DuckDB and Spark all open without a schema argument.
To convert Excel to Parquet, drop your .xlsx above. The chosen sheet is typed one column at a time and written as a Parquet file by DuckDB running in your browser, with each column carrying a real type: BIGINT, DOUBLE, BOOLEAN, DATE or VARCHAR. Pick Snappy, Zstd or no compression, then download.
Want to filter or join before you write it? Open the app
The handover from the spreadsheet world to the data world
Every analytics team has the same problem: the numbers that matter arrive as a workbook. Budget targets, a partner's monthly report, the finance team's allocations, a survey export. The pipeline is Parquet all the way down and the input is a .xlsx someone emailed.
The usual bridge is a CSV, which loses everything: the types go, the dates become ambiguous strings, and the loader on the other side has to guess it all back. Parquet keeps the schema in the file, which is the entire reason the format exists.
The other reason to convert is size. A hundred megabyte workbook of mostly repeated category values becomes a Parquet file a fraction of the size, and one that a query engine can read a single column out of without touching the rest.
The types the file ends up with
Each column is typed once, from all of its values, and that decision is handed to DuckDB explicitly rather than being sniffed a second time:
- BIGINT for a column of whole numbers, so counts and ids stay exact.
- DOUBLE for a numeric column with fractions in it.
- BOOLEAN for a column of Excel TRUE and FALSE, which is a real boolean in the file rather than the text.
- DATE for a column of ISO dates, which is what makes a partition predicate or a date filter push down at query time.
- VARCHAR for everything else, including any column with a padded code in it.
Handing the types over explicitly matters. If DuckDB were left to sniff the intermediate representation, it could disagree with the preview shown on screen, and a store code that survived every other conversion as text could become a BIGINT at the last step. Declaring the schema removes that possibility.
Worked example, and what you get back
Take the store sheet again:
store_code opened_on staff revenue active
0041 2019-03-04 12 1840.50 TRUE
0058 2020-07-19 7 975.00 FALSE
Read the result in Python and the schema is already right:
>>> import pandas as pd
>>> df = pd.read_parquet("stores.parquet")
>>> df.dtypes
store_code object
opened_on datetime64[ns]
staff int64
revenue float64
active bool
dtype: object
>>> df.store_code[0]
'0041'
No dtype argument, no parse_dates, no converters={'store_code': str}. All three of those are things you would be writing if this had come through a CSV, and forgetting the third is how the leading zeros disappear.
Compression, and which one to pick
Snappy is the default because it is universal. Every Parquet reader written in the last decade handles it, it decompresses very fast, and the size saving on typical tabular data is substantial.
Zstd produces a noticeably smaller file at a small cost in decompression speed and is supported by every current reader, including pandas via pyarrow, Polars, DuckDB and Spark. It is the right choice for something going into cold storage. Older tooling, particularly anything pinned to a pyarrow from several years ago, may not read it.
Uncompressed is there for the case where the file is about to be recompressed by something else, or where you are measuring something and want the compression out of the way.
How this runs, and what it means for your file
DuckDB is compiled to WebAssembly and runs inside the page. The first conversion downloads that engine, which is a few megabytes and then cached, so the second one is immediate.
Nothing is uploaded. That is the reason a lot of people use this rather than a server-side converter: the workbook is a budget, a payroll extract or a customer list, and sending it to somebody's endpoint to be turned into a different file format is not a trade anyone wants to make.
The practical ceiling is your tab's memory rather than a policy. A hundred megabyte workbook is comfortable; well past that, the full editor streams and is the better route.
Frequently Asked Questions
Does the Parquet file carry real column types?
Yes. BIGINT, DOUBLE, BOOLEAN, DATE and VARCHAR, decided once per column from the sheet's own values and handed to DuckDB explicitly rather than sniffed again. That is the whole advantage over routing through a CSV, which throws every type away.
Will pandas need a dtype argument?
No. The schema is inside the file, so read_parquet gives you the right dtypes with no arguments, dates included. A padded store code comes back as a string without a converters map, which is the step people most often forget with CSVs.
Snappy or Zstd?
Snappy unless you have a reason. It is read by every Parquet implementation and decompresses quickly. Zstd is meaningfully smaller and every current reader supports it, so it suits cold storage; very old pyarrow builds may not read it.
Is the workbook uploaded?
No. SheetJS reads the file and DuckDB compiled to WebAssembly writes the Parquet, both inside your browser tab. This is usually the deciding factor, because the workbooks people convert tend to be budgets, payroll extracts or customer lists.
Why does the first conversion take longer?
The DuckDB WebAssembly engine is a few megabytes and downloads on first use, then stays cached. Subsequent conversions in the same session start immediately.
How large a file can it handle?
The limit is your tab's memory rather than a rule. A hundred megabyte workbook is comfortable. Past that the full editor streams and is the better tool, and it writes Parquet too.
Related
Take the workbook into the data stack
Real types, real compression, and the file never leaves your machine.
Back to the converter