Skip to content
FormatKit

Free online JSON to XLSX converter

JSON to Excel, one column per path

Paste an array of objects and this free converter flattens it into a spreadsheet you can download as .xlsx, with nested objects becoming dotted columns such as user.address.city. It handles records that do not share the same keys — every key becomes a column, and the panel shows how many records actually carry it — and lets you switch columns off and reorder them before exporting. No signup, documents up to 5 MB, and the .xlsx is built right here in the tab rather than on a server.

  • 100% free
  • No signup
  • Up to 5 MB
  • Dotted columns
  • Column order control
Columns

Every key found across every record is listed here, with how many records actually carry it.

    Paste JSON, or load the — three records with different keys, a nested address and a 16-digit id. To read a workbook back into JSON, use Excel to JSON.

    How to convert JSON to Excel

    Three steps: paste, decide what the columns are, download the workbook.

    1. Paste the JSON

      Drop an array of objects into the left panel, load a .json file, or paste from the keyboard without selecting the panel first. The shape is recognised first and named above the editor: an array of records, an array of arrays, an array of plain values, a single object, or an object used as a lookup table whose keys can become the first column. Documents up to 5 MB parse.

    2. Shape the columns

      Every key found anywhere in the document is listed on the right with how many records actually carry it, so a field present in 12 of 400 records is obvious before you export. Untick the columns you do not want, move any of them with the arrows, or reorder the whole list by first appearance, alphabetically or by fill rate. The Arrays dropdown decides whether a list becomes one cell of JSON, a semicolon-joined string, or one column per position.

    3. Download the workbook

      Press Download .xlsx. Strings go out as text cells, JSON numbers as numeric cells, true and false as boolean cells, and null as an empty cell unless you ask for the word. Column widths come from the longest value in each column, the header row is frozen with filter dropdowns, and the file opens in Excel, LibreOffice Calc, Google Sheets or Numbers without any repair prompt.

    Technical specifications

    Accepted inputAny RFC 8259 document: an array of objects, an array of arrays, an array of scalars, a single object, or an object of objects — .json, .geojson and .txt files
    Maximum input5 MB (5,242,880 characters); nesting is flattened to 8 levels
    Column headersDotted paths in json_normalize form — user.address.city — built from the union of every key in the document, with per-column fill rates
    Cell types writtenJSON strings → text, numbers → numeric cells, true/false → boolean cells, null → empty cell or the word null, leftover objects and arrays → one cell of minified JSON
    Number fidelityLiterals longer than 15 significant digits are written as text; every other number keeps the value its literal names
    Measured speed and size1,000 records × 8 columns: 8 ms, 0.46 MB. 5,000 records: 21 ms, 2.31 MB. 20,000 records: 143 ms, 9.35 MB
    Not writtenCell styles, number formats, formulas, additional worksheets, images and charts — the package is the five required parts only
    Processing locationYour browser — the document is never uploaded to a server

    Frequently asked questions

    How do nested objects become spreadsheet columns?

    Each leaf gets a dotted path as its column header, so {"user":{"address":{"city":"London"}}} lands in a column called user.address.city. This is the same convention pandas uses in json_normalize and jq uses in its paths output, which means the header row is a set of expressions you can paste straight back into code. Flattening stops at eight levels deep; anything still nested at that point is written into one cell as minified JSON rather than exploding into hundreds of columns.

    What happens when records have different keys?

    The column list is the union of every key in the document, and a record that lacks one gets an empty cell. The panel shows the fill rate beside each column — 3/400 records is a strong hint that a key is a typo or a deprecated field rather than real data — so you can untick it before exporting instead of discovering forty empty columns in Excel. Nothing is dropped silently; a key that appears once still becomes a column unless you switch it off.

    What happens to an array inside a record?

    You choose, because there is no answer that suits both a list of tags and a list of line items. One cell of JSON text keeps ["vip","eu"] intact and reversible; joined with a semicolon gives you vip; eu, which reads better and filters worse; and one column per position produces tags.0 and tags.1, which is right for fixed-length tuples and wrong for anything that varies. Arrays of objects always take the indexed route when you pick it, giving items.0.sku, items.0.qty and so on.

    Why is my 19-digit id written as text instead of a number?

    Because a spreadsheet cannot hold it as a number without changing it. JSON puts no ceiling on the size of a number — RFC 8259 only warns that interoperability suffers past what a double can carry — while every cell in a workbook is a 64-bit binary float with 15 reliable significant digits. Write 9007199254740993 as a numeric cell and the file will say 9007199254740992. Any number whose literal does not survive that round trip is written as text and counted in the status line, so a snowflake id or a bank account number comes out intact.

    Can I choose which columns appear and in what order?

    Yes — every column has a checkbox and a pair of arrows, and the whole list can be reordered by first appearance, A→Z, or by how many records fill it. First appearance is the default because key order in the source document is usually meaningful: the API author put id first for a reason. Moving one column with the arrows switches the list to manual ordering and leaves the rest where they were.

    What if my JSON is an object rather than an array?

    A single object becomes a single row, one column per key, which is what you want for a config file or one API response. An object whose values are all objects is treated as a lookup table instead: its keys become the first column and each value becomes a row, which is the shape a database dump keyed by id usually arrives in. That behaviour is a checkbox, so an object with two dozen object-valued fields can still be exported as one wide row.

    Why are there no colours, formulas or extra sheets in the output?

    Because the writer emits the five parts an .xlsx minimally needs and no more: content types, the package relationships, the workbook, the workbook relationships and one worksheet. There is no styles part, so there are no fonts, fills, borders or number formats; no formula elements; no second sheet; no images or charts. What it does emit — typed cells, column widths, a frozen header and an autofilter — needs none of those, and leaving the rest out is what keeps the file verifiable rather than nearly-valid.

    About converting JSON to Excel

    JSON is a tree and a spreadsheet is a grid, and every JSON-to-Excel converter is really an opinion about how to squash one into the other. The tree has depth, optional keys and heterogeneous arrays; the grid has exactly two dimensions and expects every row to have the same shape. The convention that has settled on the industry — dotted paths for nested objects, indexed paths for arrays — comes from pandas.json_normalize, and it works because the header row stays machine-readable: a column called user.address.city can be turned back into the original structure without any extra metadata, which is exactly what the Excel to JSON page does when it reads a sheet in the other direction.

    The part that catches people out is numbers. JSON’s grammar allows a number of any length — RFC 8259 §6 sets no limit and merely notes that implementations widely use IEEE 754 doubles — while a spreadsheet cell is always a double, with 15 reliable significant digits and a hard ceiling at 2⁵³−1 for exact integers. A Twitter-style snowflake id, a 20-digit invoice number and a payment reference all pass through JSON unharmed and all break in a numeric cell. This page reads the source literal rather than a parsed value — the same trick the JSON viewer uses to show long integers correctly — compares it against what a double would say, and writes text when the two disagree.

    Inconsistent keys are the other reality of real payloads. An endpoint that omits refunded unless a refund happened produces records with different key sets, and a converter that takes its column list from the first record silently drops the rest. Taking the union is the safe answer, but a union over a few thousand loosely-typed records can run to eighty columns, most of them nearly empty — so the fill rate is shown beside every column, and switching one off costs a click rather than a pass through Excel afterwards.

    Where your payload is processed

    Parsing, flattening and zipping all happen in this browser tab, so the document is never uploaded and no copy of it exists anywhere but your machine. API responses pasted into a converter routinely carry customer names, email addresses and internal ids, and none of that should travel to a third party just to become a column heading.