JSON to Excel
JSON to Excel writes a real .xlsx workbook in your browser — not a CSV renamed to .xls. Numbers stay numbers, text stays text, the header row is frozen and filtered, and nested objects become explicit column paths. Nothing is uploaded.
| id | customer.name | customer.email | total | currency | tags[0] | tags[1] | shipped | note |
|---|---|---|---|---|---|---|---|---|
| ord_1041 | Ada Lovelace | [email protected] | 148.5 | GBP | priority | gift | TRUE | — |
| ord_1042 | Grace Hopper | [email protected] | 92 | USD | standard | — | FALSE | Leave with neighbour |
How does JSON to Excel work?
Almost every “JSON to Excel” converter on the web produces a CSV file with an .xls extension, and the difference matters more than it sounds. A CSV cell is text and nothing else. Excel then guesses: it reads 00123 as the number 123 and eats the leading zeros, it decides that 2026-10-03 is a date whether or not you wanted one, and it turns 1e5 into a hundred thousand. That is Excel being helpful, and there is no way to stop it because the file carries no types to disagree with.
A workbook carries types. This tool writes SpreadsheetML — the XML parts inside an .xlsx — so a JSON number becomes a numeric cell, a JSON string becomes a string cell, and a boolean becomes a real boolean. "00123" stays 00123 because the document said it was a string.
Nested objects and arrays
A spreadsheet is a rectangle and JSON is a tree, so something has to give. The choice here is an explicit path encoding, the same one the JSON to CSV tool uses: customer.name for an object member and tags[0] for an array index. The two notations are deliberately different so a column name can never be ambiguous about which it came from.
The column set is the union of every record’s fields in first-seen order. The obvious implementation reads the keys off record one and loses everything that appears later — an optional note on one order in fifty, a discount that only applies sometimes. Those fields get a column here, with empty cells everywhere else.
What the workbook contains
A bold, frozen header row so the column names stay on screen while you scroll, an auto-filter so any column can be narrowed in one click, and column widths measured from the widest value in each column rather than left at Excel’s default. The archive is written by the same ZIP writer the batch image export uses — no spreadsheet library is loaded, because the format has not changed since 2006 and a dependency for it would be the largest thing in this route’s bundle.
JSON in
[
{ "id": 1, "user": { "name": "Ada" }, "tags": ["a","b"], "vip": true },
{ "id": 2, "user": { "name": "Grace" }, "tags": ["c"] }
]Workbook cells
A1: id B1: user.name C1: tags[0] D1: tags[1] E1: vip A2: 1 B2: Ada C2: a D2: b E2: TRUE A3: 2 B3: Grace C3: c D3: (empty) E3: (empty)
How does nested JSON look once it is in a spreadsheet?
Nested objects become dotted column paths and arrays become bracketed ones, so nothing is flattened away or written as [object Object]. The column set is the union of every record, which is why the second order's note gets a column with an empty cell above it.
JSON records
[
{ "id": 1, "user": { "name": "Ada" }, "tags": ["a", "b"], "vip": true },
{ "id": 2, "user": { "name": "Grace" }, "tags": ["c"], "note": "gift" }
]Workbook cells
id user.name tags[0] tags[1] vip note 1 Ada a b true 2 Grace c gift
The values are typed cells, not text: 1 is a number, true is a boolean and the empty cells are genuinely empty. That is the difference from a CSV renamed to .xls, where every cell is a string and Excel has to guess.
What options and edge cases does JSON to Excel support?
| Parameter | Type | Default | Behaviour & edge cases |
|---|---|---|---|
| Output format | .xlsx | SpreadsheetML | A real OOXML workbook: typed cells, a frozen header, an auto-filter and measured column widths. A CSV renamed to .xls cannot carry any of that, which is the whole difference. |
| Numbers | cell type | numeric | A JSON number becomes a numeric cell, so sums and averages work immediately. A number written as a JSON string stays a string, which is what preserves product codes, phone numbers and leading zeros. |
| Arrays | explode | join | explode | Explode gives tags[0], tags[1] and keeps every element. Join collapses an array of scalars into one cell separated by your delimiter — what somebody reading the sheet usually wants, and lossy. An array of objects is always exploded, because joining it would destroy the structure. |
| Nested objects | column path | customer.name | Dotted paths for object members and brackets for array indices, so the two are distinguishable and the column set is unambiguous. A converter that pastes [object Object] into a cell is the failure this avoids. |
| Column set | union | all records | Every field that appears in any record, in first-seen order. Reading the header off the first record is the commonest way an export silently drops data. |
| Frozen header | boolean | true | Freezes row 1, so the column names stay visible while scrolling through a long export. Excel calls this Freeze Panes; it is written into the sheet view rather than left for the reader to set up. |
| Auto-filter | boolean | true | Adds the filter dropdowns to the header row. Needs at least one data row, since a filter over a header alone has nothing to filter. |
| Top-level shape | array | object | array | An array of records is the expected input. A single object becomes one row. An object whose only array member is the data — the {"data":[…]} envelope most APIs return — uses that array and says so. |
| Input size | bytes | 8 MB | Everything runs on the main thread, so above this ceiling the workbook is declined rather than attempted. Nothing is uploaded at any size. |
Frequently asked questions
Is this a real Excel file or a CSV with a different extension?
A real workbook. The output is an OOXML .xlsx: a ZIP of SpreadsheetML parts, with typed cells, a bold frozen header row, an auto-filter and measured column widths. That is the difference that matters — a CSV renamed to .xls carries no types, so Excel has to guess at every cell and guesses wrong on leading zeros, product codes and anything that looks like a date.
Will my leading zeros survive?
Yes, if the JSON had them as a string. {"sku":"00123"} writes the text 00123 and Excel shows 00123, because the cell says it is text. {"sku":123} writes the number 123, and that is the document being accurate rather than the tool losing anything. This is the single most common complaint about CSV-based exporters and the reason this one writes a workbook instead.
What happens to nested objects and arrays?
They become column paths: {"customer":{"name":"Ada"}} produces a column called customer.name, and tags becomes tags[0], tags[1]. The bracket form for arrays is deliberately different from the dot form for objects, so a column name can never be ambiguous about which it came from. Switch arrays to Join mode to get them in one cell instead — that is lossy, and it applies only to arrays of scalars.
Some records have fields others do not. Are they dropped?
No. The column set is the union of every record's fields, in the order they are first seen, so a note that appears on one order in fifty still gets its own column with empty cells everywhere else. Exporters that read the header off the first record lose those fields without saying so.
Is my data uploaded anywhere?
No. The workbook is assembled in your browser and handed straight to the download. Open DevTools, go to the Network panel, paste a document and press Download — no request carries it. That matters more here than it might seem: the JSON people put into a spreadsheet is usually a real export of real records.
How large a document can it handle?
8 MB of JSON, which is tens of thousands of records. Above that the tool declines rather than freezing the tab, because the work happens on the main thread. The workbook itself is small relative to the input: the archive holds XML text, and it is written with stored rather than deflated entries, so expect the file to be a little larger than the equivalent CSV.