CSV to JSON Converter
Drop a CSV or paste a few rows. Out comes a JSON array or JSON Lines, pretty or minified, with leading zeros left alone. It converts in your browser, so nothing uploads and there is no daily allowance to run out of.
Columns to rename or drop before the conversion? Open the app
What the JSON is usually for
CSV is what data arrives in. JSON is what code wants to be handed. Five jobs account for nearly every conversion I do in this direction:
- Test fixtures and mock responses. Someone sends 200 sample records in a spreadsheet. The frontend needs an array it can render against before the real endpoint exists.
- Seeding reference data. Country lists, tax rates, plan tiers, feature flags. Business people keep them in a sheet, the app reads them as JSON.
- Document store imports. MongoDB, Firestore, DynamoDB and Elasticsearch all ingest JSON. None of them takes a CSV without a conversion step first.
- Fine-tuning datasets. Training files for language models are JSON Lines, one example per line. Keep the prompt and completion columns in a sheet, switch Structure to JSON Lines, download the .jsonl.
- Anything spoken over HTTP. Dropping a JSON array into a request body or a fetch mock takes seconds. Dropping a CSV in there takes a parser.
Worked example: five rows and one awkward ZIP code
A store report, straight out of a spreadsheet export:
store,zip,units,restock
Fenway,02215,48,true
Mission,94110,12,false
Lakeview,60614,0,true
Midtown,30309,7,false
Old City,19106,23,false
Pretty formatting, JSON array, which is what the widget starts on:
[
{
"store": "Fenway",
"zip": "02215",
"units": 48,
"restock": true
},
{
"store": "Mission",
"zip": "94110",
"units": 12,
"restock": false
},
{
"store": "Lakeview",
"zip": 60614,
"units": 0,
"restock": true
}
]
Two rows trimmed for space, and one detail worth staring at. Boston's 02215 kept its leading zero, and because typing is decided per column, 94110 stayed a string right alongside it. One protected value protects the whole column, and the next section explains why.
Now the same report as your colleague in Munich exported it, where Excel writes store;zip;units;restock with semicolons. You do not have to configure anything. Comma, semicolon, tab and pipe are all detected from the text, and the semicolon version of this file produces character for character the same JSON.
That detection is also why copying cells straight out of a spreadsheet works. A selection from Excel or Google Sheets lands on the clipboard as tab separated text, so the paste tab reads it without you saving a file first.
JSON array or JSON Lines
The same five rows, with Structure switched to JSON Lines:
{"store":"Fenway","zip":"02215","units":48,"restock":true}
{"store":"Mission","zip":"94110","units":12,"restock":false}
{"store":"Lakeview","zip":60614,"units":0,"restock":true}
{"store":"Midtown","zip":30309,"units":7,"restock":false}
{"store":"Old City","zip":19106,"units":23,"restock":false}
- Pick the array when the whole thing has to be one valid JSON document: a request body, a config file, a fixture you import, anything a single JSON.parse has to swallow.
- Pick JSON Lines when something reads the file a record at a time. Log shippers, BigQuery and Snowflake loaders, and every language model fine-tuning format expect exactly this. A 2 GB file is readable line by line without parsing the rest.
- The formatting toggle applies to the array. Pretty gives two-space indentation, minified gives one long line. JSON Lines is always one compact object per line, because indenting it would break the one-record-per-line contract it exists for.
- The extension follows the choice. sales.csv comes back as sales.json or sales.jsonl, keeping the name you gave it.
How values get typed
CSV has no types, JSON has five, and the guessing in between is where converters quietly damage data. The rule here is deliberately narrow:
- An empty cell becomes
null. Not an empty string, and definitely not zero. - Lowercase
trueandfalsebecome booleans. TRUE, Yes and 1 are left as they are, because guessing at those is how a survey column full of Y and N ends up half converted. - A value becomes a number only when that number prints back as the identical text. 48 becomes 48, -4 becomes -4, 3.5 becomes 3.5.
- Everything that fails the round trip stays a string: 02215 (a number would print as 2215), 2.40 (would print as 2.4), +7, values with a stray leading space, and 1e3.
- Anything longer than 16 characters stays a string, as does any long digit run that would lose precision. A 17-digit order number arrives intact rather than rounded to the nearest thousand.
- Everything else is a string, unchanged, including dates. 2026-03-14 is not turned into a timestamp, because there is no way to know which timezone you meant.
The consequence in the worked example is worth planning for. A ZIP code, phone number or account ID that happens to have no leading zero is indistinguishable from a quantity, so it gets typed as one. If a downstream system needs those quoted, the dependable fix is a value that cannot be read as a number at all, such as a code prefix.
Gotchas worth knowing
- Quotes and line breaks inside fields survive. A cell written as
"He said ""hi"", then left"becomes one JSON string with ordinary quote characters in it. A cell containing a line break stays a single value, escaped the way JSON requires. - A byte order mark is stripped. Files saved by Excel often start with an invisible marker. Left alone it becomes part of the first key name, which produces a bug that survives three rounds of debugging because the key looks correct on screen.
- Ragged rows are padded, not rejected. Rows are widened to match the longest one and the widget tells you how many it padded. If a data row is wider than the header, that extra field arrives under a generated name like column_5. Blank header cells get the same treatment.
- Duplicate header names collapse. Two columns both called id produce a single id key holding the value from the right-most one. Rename one of them before converting.
- Dotted headers do not create nesting. A column named user.name becomes a key spelled user.name. The output is one flat object per row, by design.
- 100 MB is the ceiling here. No row limit, no metering, but past 100 MB the browser tab is the wrong tool and the widget offers the full editor instead.
Frequently Asked Questions
Is my CSV uploaded to a server?
No. The file is read and converted by JavaScript running in your tab, and there is no upload endpoint behind this page. Nothing is stored between visits, so a reload gives you an empty box.
Can it produce nested JSON?
No. Every row becomes one flat object, and a column called user.name becomes a key spelled exactly that, dot included. If you need real nesting, convert here and reshape afterwards. Going the other way, our JSON to CSV tool flattens nested objects into the same dotted columns.
Why did every ZIP code stay a string when most look like numbers?
Typing is decided per column, not per cell. A column becomes numbers only when every value in it prints back as identical text. 02215 would print as 2215, so the whole zip column stays strings, including 94110. One leading zero is enough to protect the entire column.
What is JSON Lines and when should I choose it?
One JSON object per line, with no wrapping array and no commas between records. Pick it for log pipelines, warehouse loads, and fine-tuning datasets for language models, all of which read one line at a time. The download is named .jsonl.
Does it read semicolon or tab separated files?
Yes, and you do not have to say so. Comma, semicolon, tab and pipe are sniffed from the text itself, which covers the semicolon files that European Excel installs produce by default.
How large a file can it take?
Up to 100 MB in this page, with no row cap and no daily quota. Larger files get handed to the full editor, which streams the data instead of holding all of it in memory.
Related
Convert your CSV to JSON
No sign-up, no upload, no row cap. Pick an array or JSON Lines, copy the result or download the file.
Back to the converter