CSV ↔ JSON Converter

Convert between CSV and JSON: RFC 4180 quoting, an auto-detected delimiter, typed values, and a preview of the table.

JSON

3 rows × 4 columns · delimiter comma · everything runs in this page, nothing is uploaded.

Preview · 4 rows
#toolkindstarsfree
2CSV to JSONconverter128true
3JSON, YAMLconvertertrue
4chmod calculatortool42false

Runs in your browser. Nothing you enter is sent anywhere.

How to use it

Pick CSV → JSON or JSON → CSV and paste into the box, or choose a file under Or read a file: it’s read in the page, never uploaded, and its extension sets the direction.

  1. Choose a delimiter: Auto, Comma, Semicolon, Tab or Pipe. Auto detects it when reading CSV and means a comma when writing it.
  2. First row holds the column names makes each row an object keyed by the header; untick it for arrays. In JSON → CSV it reads Write the column names as a header row.
  3. Read 123, 1.5, true, false and empty cells as numbers, booleans and null applies to CSV → JSON only. Untick it to keep every cell a string.
  4. Copy the result, or Download it as table.json or table.csv (or your file’s name).

Under the result are the row and column counts, the delimiter used, any Warnings (ragged rows, repeated names, delimiter ties; none stop the conversion) and a Preview table. Switching direction carries the result into the input for a round trip.

Examples

A contacts export, with the defaults (Auto, both boxes ticked):

id,name,zip,active,score
1,"Lovelace, Ada",02134,true,9.5
2,Grace Hopper,10001,false,
3,"Alan ""Al"" Turing",,true,1.50
[
  {
    "id": 1,
    "name": "Lovelace, Ada",
    "zip": "02134",
    "active": true,
    "score": 9.5
  },
  {
    "id": 2,
    "name": "Grace Hopper",
    "zip": 10001,
    "active": false,
    "score": null
  },
  {
    "id": 3,
    "name": "Alan \"Al\" Turing",
    "zip": null,
    "active": true,
    "score": "1.50"
  }
]

02134 and 1.50 stay strings because as numbers they’d lose a zero; 10001 doesn’t, so the zip column now mixes types. Untick the typing box to keep one type per column.

A semicolon file with decimal commas, with Auto:

product;price;stock
Widget;1,99;1.200
Gadget;12,50;80
[
  {
    "product": "Widget",
    "price": "1,99",
    "stock": "1.200"
  },
  {
    "product": "Gadget",
    "price": "12,50",
    "stock": 80
  }
]

All three lines split the same way on ;, and only two hold a comma, so Auto picks semicolon. 1.200 would come back as 1.2, so it stays a string.

API records, with JSON → CSV, Auto and the header box ticked:

[
  {"id": 1, "name": "Ada", "tags": ["admin", "ops"]},
  {"id": 2, "name": "Grace \"Amazing\" Hopper", "email": "[email protected]"},
  {"id": 3, "name": "Alan", "tags": null, "note": "line one\nline two"}
]
id,name,tags,email,note
1,Ada,"[""admin"",""ops""]",,
2,"Grace ""Amazing"" Hopper",,[email protected],
3,Alan,,,"line one
line two"

Columns follow the order keys first appear, integer-like names such as 2024 included. A missing key and null give an empty cell, the array is written as JSON text, and fields with a comma, quote or line break are quoted.

An unclosed quote, with CSV → JSON:

id,comment
1,"Arrived late
2,Fine

The error is The quoted field that opens on line 2 is never closed.

Good to know

  • Quoting follows RFC 4180. A field holding the delimiter, a " or a line break is quoted, with inner quotes doubled. Reading accepts CRLF, LF or CR and skips blank lines; writing ends every row with CRLF. A quote opens a field only as its first character, so 5" screen is plain text.
  • An unbalanced quote can swallow rows. The next " in the file closes it, so the lines between become one cell. A low row count, or a warning like Row 2 has 3 fields; the header has 2., points at it.
  • Typing converts only cells that write back as spelled. -12.5 becomes a number; 007, 1.50, -0, 1e3, 0x1F and 9007199254740993 (past 2^53, so inexact as a double) stay strings, as do TRUE and null. An empty cell becomes null.
  • Auto reads the first 10 lines and picks the character that splits the most of them into the same number of fields, counting only outside quotes. Ties go to comma, then semicolon, tab and pipe, with a warning.
  • Header gaps get positional names. An empty header cell, or a column only a longer row reaches, becomes column1, column4 and so on. A short row’s missing fields are null, typing or not. When two columns share a name, the later one wins, with a warning.
  • JSON numbers are written as spelled, nested ones too: 1.10, 1e3 and 12345678901234567890 don’t become 1.1, 1000 and 12345678901234567000.
  • JSON errors name the line and column: [{"id": 1,}] gives Line 1, column 10: A trailing comma before "}" is not allowed in JSON.
  • Input is limited to 1,000,000 characters, and JSON to 500 levels of nesting. A leading byte order mark is dropped, and none is written. The preview shows the first 50 data rows; Copy and Download carry all of them.

Questions

How do I convert CSV to JSON?

Paste it with CSV → JSON selected: each row becomes an object keyed by the header row, or an array if you untick First row holds the column names.

How do I convert JSON to CSV?

Choose JSON → CSV and paste an array of objects: the keys become the header and each object a row. A wrapper like {"data": [...]} fails with Top-level JSON must be an array: one object per row, or one array per row.; paste the inner array. To give a nested field its own column, flatten it first: jq 'map({id, city: .address.city})'.

How do I convert CSV to JSON in Python or the terminal?

In Python, csv.DictReader keys each row by the header:

import csv, json
with open("data.csv", newline="", encoding="utf-8-sig") as f:
    print(json.dumps(list(csv.DictReader(f)), indent=2))

Values stay strings; utf-8-sig drops a byte order mark. In a shell, Miller does it in one line: mlr --icsv --ojson cat data.csv.