DevKitHub

JSON & Data

JSON to Excel Converter — Download a Real .xlsx File

Paste an array of objects to download an .xlsx workbook with one row per object, a bold frozen header and real number, true/false and date cells. The file is built in this page.

4 lines

Workbook

Sheets
Sheet1 (7 columns)
Table
2 rows × 7 columns, plus a header row
Cells
9 text cells · 2 numbers · 2 true/false · 1 empty
File size
2.8 KB .xlsx

Preview of Sheet1

The first rows of the sheet as Excel will show them: numbers and dates right-aligned, text left-aligned.
idnamejoinedordersvipaddress.cityaddress.postcode
0042Ada Lovelace2024-02-2912TRUELondonN1 9GU
0043Grace Hopper2026-09-29T13:45:003FALSEArlington

Numbers and dates are right-aligned and text left-aligned, as Excel aligns them.

The workbook is built in this page and never uploaded. Strings stay text, so “007” keeps its zeros and “=1+2” is not run as a formula. Need a CSV instead? JSON to CSV flattens the same way.

This tool runs entirely in your browser. Your input is never uploaded, stored or logged.

How it works

The JSON is flattened exactly as the JSON to CSV converter does it. Each nested object becomes columns named by path — address.city, address.geo.lat — and the header is the union of every path in every row, so a field only some objects have still gets a column, next to its siblings. An array is written as JSON text in one cell, or with Expand arrays as one column per element (tags.0, tags.1). An empty object or array keeps its own cell as {} or []. JSON Lines, one object per line, is read too, and an object whose values are all arrays of objects — the shape Excel to JSON produces with All sheets — becomes one sheet per key. An array of arrays is taken as rows already, without a header.

The difference from a CSV is that every cell has a type. A JSON number is written as a number and true or false as an Excel boolean, while a string is always text, even when it looks like a number: "007" stays 007 with its zeros, and "=1+2" is stored as the characters =1+2, not a formula, because the cell says it is text. That also means formula injection cannot happen the way it does when a CSV is opened. Dates are the one place a string can change type, and only when you ask: with ISO dates on, 2026-09-29 and 2026-09-29T13:45:00 are written as Excel date serials with a yyyy-mm-dd or yyyy-mm-dd hh:mm:ss format; a timestamp with Z or an offset is converted to UTC, since an Excel date has no time zone, and a date before 1900, which Excel cannot store, stays text.

Precision is lost before conversion begins in one case. JSON.parse turns an integer past 2^53 into the nearest number JavaScript can hold, so 12345678901234567890 becomes 12345678901234567000; the source text is scanned for such integers and any that were rounded are reported. Excel adds a second limit, 15 significant digits, so a 16-digit number is flagged as well. Ids belong in quotes, as strings. The workbook itself is written without a library: the sheet XML, a shared string table, a stylesheet with a bold header font and the date formats, column widths estimated from the content, and a ZIP compressed with this page’s own DEFLATE encoder. Sheet names are cut to Excel’s 31 characters without \ / ? * : [ ], and control characters XML cannot carry are removed, with a warning.

Common problems

Every example below is run against this tool in our test suite, so what it says here is what the tool actually does.

Row 1 is a number, not an object.

[1,2]
Why:
A sheet needs named fields to build its header row, and an array of plain values has none. The converter accepts an array of objects, an array of arrays, or an object of arrays.
Fix:
Wrap each value in an object, as in [{"value": 1}, {"value": 2}], or paste the array of objects that holds your rows.

Expected property name or '}'

[{'id': 1, 'active': True}]
Why:
This is how Python prints a list of dicts, not JSON: single quotes, and True, False and None where JSON has true, false and null.
Fix:
Produce the text with json.dumps(rows) in Python rather than print(rows) or str(rows).

A long id ends in 000 in the spreadsheet.

Why:
JSON.parse rounds any integer past 2^53, so 12345678901234567890 is 12345678901234567000 before the workbook exists, and Excel itself keeps only 15 significant digits of a number.
Fix:
Send ids as strings in the JSON, as in "id": "12345678901234567890". Strings are written as text cells with every digit.

Dates are left-aligned text, not dates.

Why:
JSON has no date type, so a date is just a string, and strings are written as text unless ISO dates is turned on. Only ISO 8601 dates are converted; 29/09/2026 means different days in different countries.
Fix:
Turn on ISO dates, and send dates as 2026-09-29 or 2026-09-29T13:45:00 from the source.

Excel shows a green triangle: Number Stored as Text.

Why:
The value was a JSON string such as "42", so it was written as text, which is right for an id or a phone number and wrong for a quantity.
Fix:
Send quantities as JSON numbers (42, not "42"). For ids and phone numbers the triangle is harmless and can be dismissed.

Frequently asked questions

Is my JSON uploaded to build the file?
No. The .xlsx is assembled by JavaScript in this page — the XML, the shared strings, the styles and the ZIP compression — and handed to your browser as a download. Nothing is sent to a server.
How are nested objects turned into Excel columns?
Each nested field becomes a column named by its path, such as address.city, and the header is every path seen in any row. Arrays are written as JSON text in one cell, or with Expand arrays as one column per element.
Will numbers and dates be real Excel numbers and dates?
Numbers and true/false values are typed cells, so they sum and sort as numbers. Dates become real dates when ISO dates is on and they are written as ISO 8601, such as 2026-09-29; otherwise they stay text.
Can I get several sheets in one workbook?
Yes. Paste an object whose values are arrays of objects, such as {"Orders": [...], "Customers": [...]}, and each key becomes a sheet with that name, shortened or changed where Excel’s rules for sheet names require it.

Last updated