fileformer
search⌘KtranslateENexpand_moreupload_fileConvert
Converters8 file families · 44 direct conversions
What changes in a conversionarrow_forward
home/developer-tools/json-to-csv

JSON to CSV Converter

Turn an API response into a spreadsheet.

Paste JSON and get a table. Nested objects become dotted columns like address.city, lists are joined or split into rows, and you choose which columns to keep. The CSV opens cleanly in Excel, Numbers and Google Sheets.

groupUsersshopping_cartOrderssensorsSensor log
Lists: keep in one cellLists: one row each
commasemicolontab
jsonvalid · 3 records
table preview · click a column to drop it3 rows × 8 columns
view_columnidview_columnnameview_columnemailaccount_treeaddress.cityaccount_treeaddress.postcodeview_columntagsview_columnactiveview_columnphone1Ada Okaforada@example.comLeedsLS1 4APadmin; betatrue-2Sam Reidsam@example.comGlasgowG1 1XQbetafalse-3Priya Nairpriya@example.comCardiff--true07700 900123
nested columns2empty cells4number columns1csv size0.2 KB
csv · first linesid,name,email,address.city,address.postcode,tags,active,phone1,Ada Okafor,ada@example.com,Leeds,LS1 4AP,admin; beta,true,2,Sam Reid,sam@example.com,Glasgow,G1 1XQ,beta,false,
content_copyCopy CSVdownloadDownload .csv
~/trees-into-grids

JSON is a tree. A spreadsheet is a grid. Something has to give.

One order with two items can't fit in one row without a decision. Here's the same record three ways. Pick the one that matches what you'll do with the spreadsheet.

{ "order": "A-1001", "customer": { "name": "Ada Okafor", "city": "Leeds" }, "items": [ { "sku": "TR-10", "qty": 1 }, { "sku": "SK-02", "qty": 2 } ]}
Stringifykeep JSON in cellsFlattendotted columnsExplodeone row per item
ordercustomer.namecustomer.cityitemsA-1001Ada OkaforLeeds[{"sku":"TR-10",…}]
Objects become dotted columns you can filter on. Lists of objects still need a decision; this is what the “Lists: keep in one cell” setting does.
~/excel-helpfully-changes-it

Four values Excel quietly changes when it opens a CSV.

A CSV has no types, so Excel guesses. Each card shows what's in the file, what Excel displays, and whether our "protect for Excel" option would keep it intact.

shieldProtect for Excel: on
Leading zeros
in the file'07700 900123excel shows07700 900123
Phone numbers and postcodes like 01234 lose their leading zero because Excel treats them as numbers.
Dates from codes
in the file'3-12excel shows3-12
Sizes, versions and part codes that look like dates are converted and can’t be changed back.
Long IDs
in the file4580219876543210excel shows4.58022E+15
Numbers over 15 digits are rounded. Card and order IDs are silently corrupted; keep them as text. Protection can’t fix this one: import the column as Text instead.
Accents
in the fileZoë Müllerexcel showsZoë Müller
Without a byte-order mark, older Excel reads UTF-8 as Windows-1252. We add the mark when protection is on.
~/there-and-back-again

CSV has no types. Here's what doesn't survive the trip back.

JSON knows numbers, strings, true, false, null, arrays and objects. A CSV cell is only text. Converting is easy; reading it back means something has to guess the types again. Each value below is written to CSV the way this converter does, then read back by three typical readers. A row counts as surviving only if the value that comes back is exactly what went in.

Strings onlyPython csv, Go encoding/csvAuto-typedpandas, Papa Parse dynamicTypingSpreadsheetExcel or Sheets opening the file
7 / 14Auto-typing restores numbers and booleans, but turns numeric-looking strings into numbers and can’t tell empty strings from null.
JSON valuetypeCSV cellread backwhat happened
42number4242check_circleComes back unchanged.
"007"string0077cancelLeading zeros dropped: a postcode or ID becomes a number.
9007199254740993number90071992547409929007199254740992errorLost before CSV was involved: JSON.parse turns this into 9007199254740992, because doubles can’t hold integers above 2⁵³ exactly. IDs this big should travel as strings.
0.1number0.10.1check_circleComes back unchanged.
truebooleantruetruecheck_circleComes back unchanged.
nullnull(empty)nullcheck_circleComes back unchanged.
""string(empty)nullcancelEmpty string and null both become an empty cell, so they can’t be told apart afterwards.
"null"stringnullnullcancelpandas reads the text null (and NA, N/A, NaN) as missing by default; pass keep_default_na=False to keep it.
"1e5"string1e5100000cancelA string that looks like a number becomes one.
"2026-03-04"string2026-03-04"2026-03-04"check_circleComes back unchanged.
"12345678901234567890"string1234567890123456789012345678901234567000cancelParsed as a 64-bit float, which keeps about 16-17 significant digits; the last digits are lost.
["a","b"]array"[""a"",""b""]""[\"a\",\"b\"]"cancelWritten as JSON text. It comes back as a string unless you JSON.parse that column yourself.
"line\nbreak"string"linebreak""line\nbreak"check_circleComes back unchanged.
"=1+1"string=1+1"=1+1"check_circleComes back unchanged.
lightbulbNo single reader gets everything back. To round-trip safely, keep a schema with the CSV: tell the reader each column’s type (dtype in pandas, a column format of Text in Excel), write IDs and postcodes as strings, and keep nested data as JSON text in its own column.
~/reference

The two specs, side by side.

JSON is precisely defined by RFC 8259 and ECMA-404. CSV only has RFC 4180, an informational description of common practice that many tools ignore. These are the rules that matter when converting between them.

JSONapplication/jsonSpecRFC 8259 and ECMA-404, both 2017EncodingUTF-8 required between systems; no byte order markTypesobject, array, string, number, true, false, nullNumbersNo size limit in the grammar. RFC 8259 warns that only ±(2⁵³−1) is safe across systemsNot allowedNaN, Infinity, trailing commas, comments, single quotesKeysDuplicates are allowed by the grammar but behaviour is undefinedOrderObject members are unordered; arrays keep order
CSVtext/csvSpecRFC 4180 (2005), informational onlyEncodingUnspecified; the charset parameter says. Excel needs a BOM to detect UTF-8TypesNone. Every field is textLine breaksCRLF between records; a final line break is optionalQuotingFields with commas, quotes or line breaks must be in double quotes; a quote inside is doubled ""HeaderOptional, signalled by header=present in the MIME typeDelimiterComma in the RFC; semicolon in many European locales; tab in TSV