ApexAutomation
Apex Automation

Apex Automation free tools

JSON to Excel

Nested arrays become sheets, still joined to the row they came from

The easy half of this job is an array of flat records. The half that costs you an evening is an order with line items inside it, because a spreadsheet has no place to put them. Every other converter answers that by cramming the array into one cell or by flattening it into column names nobody can read. Here each nested array gets a sheet of its own, and every row in it carries the key of the row it belongs to.

  • Free to use
  • No account needed
  • Nothing uploaded
  • No row limit

Drop a JSON file here

or

The shape of the file is worked out for you, and if the records are buried inside an envelope you can point at them yourself.

What your file needs

  • .json, .jsonl or plain textAn array of records, a single object, or an object whose values are arrays. JSON Lines, one record per line, is recognised and read as a list.
  • Any nesting depthObjects inside objects become dotted columns. Arrays become sheets of their own, and an array inside that array becomes another sheet below it.
  • Any number of recordsNo cap and no sign up. Excel stops at 1,048,576 rows in one sheet, so a sheet past that is split and the page tells you it happened.
  • Any encodingUTF-8 and UTF-16, with or without a byte order mark. A zip, an .xlsx or a PDF dropped here is named as what it is instead of failing strangely.
  • Records that do not matchOne record with ten fields and the next with three is fine. Every key that appears anywhere becomes a column, and a record that lacks one leaves that cell blank.
  • Keys in any languageKeys with dots, spaces, accents or Chinese characters are kept as written. Two different paths that want the same column name do not overwrite each other.
  • IDs that must not be roundedA reference past fifteen digits is written as text, because Excel keeps fifteen and changes the rest without saying so. A leading zero survives for the same reason.
  • An API envelope around the recordsResponses wrapped in data, items, results or value are spotted, and you pick which array to convert.

What will not work. A file that is not valid JSON comes back with the line and column where it breaks, not a converted guess. A .xlsx or a CSV is the wrong way round for this page. And Excel cannot tell an empty string from an empty cell, so a field holding "" comes out blank, the same as a null.

Why line items break every other converter

Take an order with two lines in it. There is one order and there are two lines, so there is no single row that holds both without either repeating the order or hiding the lines. A spreadsheet is a rectangle and the data is not.

{ "id": "00721", "total": 79.5,
  "lines": [ { "sku": "A-1", "qty": 2 },
             { "sku": "A-2", "qty": 1 } ] }

There are only three answers, and most tools pick one without telling you which. Put the array in one cell as JSON text, which looks tidy and cannot be sorted, filtered or summed. Repeat the order across two rows, which doubles the total and quietly breaks anyone who adds up that column. Or name the columns lines.0.sku and lines.1.sku, which works until a third line appears and the columns change shape.

The fourth answer is the one a database would use, and it is the one here.

The order goes on one sheet and the lines go on another. Every line carries the key of the order it belongs to and its position in the array. Nothing is repeated, nothing is hidden, and the two sheets can be put back together with a lookup, a pivot table or a Power Query merge. It is the shape your data already had, written down honestly.

What is not claimed. No accuracy percentage and no promise that the workbook will be the shape you had in mind, because only you know that. What is claimed is narrower and you can check it on your own file: every value that went in comes out in exactly one cell, and every child row points at a parent row that exists. The counts for your file are printed above the table each time you convert.

The cells that look right and are not

A converter that writes everything as text is safe and useless: you cannot sum a column of text, and the dates sort alphabetically. A converter that writes everything as whatever Excel guesses is worse, because it damages data and says nothing. Both are common.

Excel keeps fifteen significant digits. That is not a bug, it is the format. A sixteen digit reference such as a Stripe charge, a bank transaction ID or a Snowflake key goes in whole and comes back with the last digit changed to a zero, and the cell still looks perfectly normal. The same thing happens the other way round to a postcode: 01067 becomes 1067 and Dresden turns into a number.

Dates have three traps of their own and all three are silent. A string like 2026-02-30 is not a date, but JavaScript turns it into the second of March without complaint, so it stays text here instead. A timestamp carrying an offset like +05:00 has no home in a spreadsheet, because Excel has no timezone at all, so converting it would move the clock by five hours and say nothing: it stays text too. And Excel's day numbering is unreliable before March 1900, thanks to a leap year that never happened, so anything older stays text.

So each value is decided on its own. A number that fits in fifteen digits is written as a real number. Anything longer is written as text, because the digits matter more than the arithmetic. A string that is an ISO date becomes a real date cell with a date format on it. True and false become real booleans. Everything else stays text, and the page lists every value where this rule did something, so you can see it rather than discover it later.

There is one more thing a spreadsheet does that nobody expects. A cell whose text begins with an equals sign, a plus, a minus or an at sign is treated as a formula when the file is opened. In a file you were sent, that is how a spreadsheet runs somebody else's instructions on your machine. Those values are prefixed so they stay text. If you need them raw, the checkbox above the convert button turns the guard off.

Excel's own limits, guarded rather than mentioned

Every tool in this category that mentions these limits mentions them in a help page. None of them act on them, so a file that crosses one produces a workbook that will not open, or opens with data missing. The limits are fixed and they are not secret:

Sheet names are the quiet one. Excel also forbids a colon, a backslash, a slash, a question mark, an asterisk and square brackets in a sheet name, and a workbook that contains one does not report an error. It fails to open.

The records are rarely at the top of the file

A real API response is wrapped. There is a status, a page number, a count, and the records you actually want are two levels down inside data or items or results. Paste that whole response into most converters and you get a one row sheet describing the envelope.

When a file has more than one array in it, the arrays are listed with the number of records in each, and the one that holds records rather than plain values is suggested first. You pick. You can also write the path yourself in the usual notation, so $.data.items[*] converts the records and leaves the envelope out of it.

The workbook says how to put itself back together

A workbook split across five sheets is only useful if you can tell which sheet joins to which. That is knowledge the converter has and then throws away, so every one of these files arrives as a pile of tabs and the person who opens it has to work the relationships out by reading them.

So the first sheet is a map. It lists every sheet, how many rows it holds, which sheet it came from, which column joins the two, and the lookup formula that rejoins them. Paste the formula into the child sheet and the parent's fields come back alongside the lines. Nothing to work out and nothing to remember.

And then there is the question nobody else lets you ask: did it convert correctly?

Next to the download button is a button that takes the workbook apart and builds your original JSON back out of it, then compares the two key by key, value by value, and in order. If anything had landed in the wrong sheet, lost its place in an array or gained a key it never had, the two would not match and the page would say exactly where. It is the same check the test suite runs on a thousand generated files before anything ships, pointed at your file instead.

Why this is the strongest check there is. Counting values proves nothing was lost. It cannot prove anything landed in the right place, because the total comes out the same either way. Rebuilding proves placement and structure together: there is only one arrangement of sheets that turns back into the file you started with.

What has actually been tested

Every figure here is a test run that has to pass before anything reaches this page. If one fails, nothing ships. A number on a page that nothing checks goes stale, so a test reads this page, pulls out every figure in it, and compares each one with the code behind it.

184automated checks, all passing
16suites, each runnable on its own
400generated workbooks read back by a different program
29deliberate faults, every one caught
0bytes uploaded
The workbook is read back by something that did not write it Four hundred generated files are converted, written to disk and then opened by openpyxl, which is a separate Python implementation with no connection to the code here. Every value in the original JSON is matched against the cells that came out. A number written as text, a date that lost its time, or a value that landed in the wrong sheet all fail that comparison.
Every test is broken on purpose before it is trusted Twenty deliberate faults are injected into the code one at a time, the suites are run, and the fault is reverted. A fault that survives means the tests have no opinion about it, and the missing test gets written. One did survive the first sweep: the sheet name limit could be raised from thirty one to one hundred and twenty and nothing complained, because the test was reading the same constant it was meant to be checking.
The page is opened in a real browser on every run A browser loads this page under the same security policy it ships with, converts the example, checks that the counts match, opens the FAQ, lands on a wrong URL to see the 404 page keeps its styling, and then cuts the network and converts again to prove nothing was being sent. The layout is measured at seven screen sizes and with the browser text turned up, because a page that works and looks broken is still broken.
The counting is not the whole check, and that was learned the hard way Two thousand generated files passed the count with nothing flagged. The same files, written out and read back by the other program, had values missing. The count proves nothing was lost. It does not prove anything landed in the right column, and that needs its own check.

What it will not do

Questions people ask first

Does anything get uploaded?

No. The file is read by code already sitting in this browser tab and the workbook is written here too. There is no upload endpoint and no server waiting to receive anything. You can watch your browser's Network tab while you use it, or disconnect after the page has loaded and carry on working offline. A test does exactly that on every run: it cuts the connection after load and converts a file anyway.

What happens to a nested array like line items?

It becomes a sheet of its own. Each row in that sheet carries the key of the parent row it came from and its position inside the array, so an order and its lines stay joined and can be rebuilt with a lookup, a pivot or a Power Query merge. An array inside that array becomes a third sheet, linked the same way. Arrays of plain values, such as a list of tags, also get a sheet, so nothing is crammed into a cell.

Is there a row limit?

No. The free tools in this category stop at a few thousand rows, or a few megabytes, because they are front ends to a paid API and that is where the free tier ends. The work here happens in your own browser, so the only limit is your machine. Excel itself stops at 1,048,576 rows in a sheet, and when a sheet would pass that it is split into numbered parts and the page tells you.

Why is my long reference written as text?

Excel keeps fifteen significant digits. A sixteen digit ID stored as a number comes back with its last digit changed, and the cell looks completely normal, so this is the kind of damage nobody notices until a lookup stops matching. Anything past fifteen digits is written as text instead, and every value this happened to is listed above the table.

What is the column called _row for?

It is the key that joins a parent sheet to its children. A child sheet has _parent, which holds the _row value of the row it came from, and _index, which is its position in the array. If your own data already has a field called _row, the generated column is renamed instead and the page says so, because two columns with the same name is a problem you would have to untangle later.

Can I convert only part of the file?

Yes. When the file holds more than one array, they are listed with the number of records in each, and you pick. You can also write the path in the usual notation, so $.data.items[*] converts the records inside an API envelope and leaves the status and paging fields out of the workbook.

Why does a value start with an apostrophe?

Because it began with an equals sign, a plus, a minus or an at sign, and a spreadsheet treats those as formulas when the file is opened. In a file you were sent by somebody else, that is how a spreadsheet runs their instructions on your machine. The apostrophe keeps the value as text. If you need the raw characters, turn the guard off with the checkbox above the convert button and convert again.

What is the Sheet map sheet at the front of the workbook?

It is a short table of what is in the rest of the file: every sheet, how many rows it holds, which sheet it came from, which column joins the two, and the lookup formula that rejoins them. A workbook split across several sheets is only useful if you know how they relate, and that is knowledge the converter has and usually throws away. It only appears when there is more than one sheet.

Can I check that it converted my file correctly?

Yes, and that is unusual, so it is worth saying how it works. Next to the download button is a button that takes the converted workbook apart and builds your original JSON back out of it, then compares the two key by key and in order. If a value had landed in the wrong sheet or lost its place in an array, the two would not match and the page would name the exact path where they differ. The same check runs on a thousand generated files before anything ships.

Does it read JSON Lines?

Yes. If the file is not valid JSON as a whole but every line is a valid object on its own, it is read as a list of records and the page says that is what happened. Plenty of exports and log files come in this shape.

Tell us what would make this better

If a file comes out in a shape that is wrong, send us the shape and one line is enough. You do not need to send the real data. toolssupport@apexautomationteam.com

  • A JSON shape that comes out wrong, or comes out confusing
  • A layout your spreadsheet or BI tool wants that is not here yet
  • Anything in the tool that is broken, or just quietly annoying
  • A version of this wired into your own platform or workflow
  • Something else altogether, built to your spec

Email our team See what we build

A value that lands in the wrong cell jumps the queue. Everything else is a feature request and waits its turn.