XLSX to JSON — the header-to-key contract and what your code has to tolerate
A sheet is a grid; JSON is objects. The conversion is a contract: the first row becomes the keys, each following row becomes one object, and every cell value is written as a string. Nothing is typed, nothing is calculated, and rows that are entirely empty are skipped rather than emitted as empty objects.
Cell formatting, colours, column widths and merged ranges are dropped; only stored values survive.
Processed on your device. Files aren’t sent anywhere.
The header row becomes the keys
Whatever the first row contains becomes the property names. A sheet with no header row produces objects keyed by generic column names, and the column names you meant are gone.
Two edge cases are handled rather than rejected:
- A blank header cell becomes a generated name such as column_3, so the value in that column is not lost.
- A repeated header name gets a numeric suffix, so two columns called Notes appear as Notes and Notes_2.
- A sheet whose first row is data, not labels, produces objects keyed by that data.
Questions
Why are numbers quoted in the JSON?
What happens to a blank cell?
Do extra sheets appear?
Are formulas evaluated?
Empty cells become null
An empty cell is written as null, not as an empty string and not as zero. That is the closest honest mapping: the cell has no value, and null says so.
null is a claim about the cell, not about the column: this cell had nothing stored in it.
Why an empty quantity is not exported as 0
Everything else arrives as text
Numbers, dates and booleans all leave as strings. A quantity of 12 arrives as "12". A date that reads 12 Mar 2024 arrives as "12 Mar 2024".
| Cell | JSON value | Type |
|---|---|---|
| 12 | "12" | string |
| 12 Mar 2024 | "12 Mar 2024" | string |
| (empty) | null | null |
| 0 | "0" | string |
Coercion belongs to the receiving code
Turning "12" into 12 is a decision about your schema, not a fact about the sheet. A leading-zero identifier must stay a string; a quantity should be parsed. Doing that in your own code keeps the choice visible instead of burying it in a converter.
When objects are the wrong shape
Sheet mode decides what happens to extra sheets. With First sheet you get objects from one sheet. With All sheets every sheet is appended into the same array, so a lookup sheet and a summary sheet end up as records in one list with nothing marking where each came from.
- Pick First sheet unless you genuinely want every sheet.
- Convert and download the JSON.
- Parse it and check the key names against your schema.
- Check which values are null before you assume a column is complete.
- Coerce numbers in your code, not in the spreadsheet.