iKit
Guide · 10 min read ·

CSV to JSON: The Complete 2026 Guide for Developers

How CSV to JSON conversion really works in 2026 — RFC 4180 quoting rules, delimiter detection, BOM and encoding traps, and safe type inference.

CSV to JSON: The Complete 2026 Guide for Developers

CSV to JSON: The Complete Guide for Developers, Analysts and PMs

You export a report, get a .csv, and need it as JSON for an API, a seed script, or a chart library. A CSV to JSON conversion looks like a one-liner until a customer name contains a comma, a zip code loses its leading zero, or Excel writes a delimiter you didn't expect. This guide covers what actually happens between the two formats and where converters quietly get it wrong.

TL;DR

  • CSV has no real standard — RFC 4180 documents common practice, not law.
  • Quoted fields can contain commas and newlines; never split on ,.
  • Type inference is a trap: IDs and zip codes must stay strings.
  • A UTF-8 BOM fixes Excel but corrupts your first JSON key.
  • Browser-side conversion keeps customer data off other people's servers.

What CSV to JSON conversion actually does

The two formats disagree about something fundamental. CSV is a grid: rows and columns, every cell a string, no types and no nesting. JSON is a tree with typed leaves. Converting between them is not a reformat — it's an interpretation, and every converter makes assumptions on your behalf.

From rows to an array of objects

The standard output shape takes the header row as keys and emits one object per data row:

id,name,city
1,Ada Lovelace,London
2,"Hopper, Grace",New York

becomes

[
  { "id": "1",
    "name": "Ada Lovelace",
    "city": "London" },
  { "id": "2",
    "name": "Hopper, Grace",
    "city": "New York" }
]

Note row 2. The comma inside the quoted name is data, not a delimiter. That single case is what separates a real parser from a split(',').

Array of arrays, when there's no header

If the file has no header row, the honest output is an array of arrays. Inventing keys like field1, field2 is sometimes convenient, but it bakes a guess into your data. Most tools, including the iKit CSV ↔ JSON Converter, let you toggle whether the first row is a header.

What gets lost in both directions

CSV has no concept of null — an empty field could be an empty string or a missing value, and the file cannot tell you which. JSON has no concept of column order beyond object key order. Round-tripping CSV → JSON → CSV is lossy in small, annoying ways.

Why does my CSV break when a field contains a comma

This is the single most common CSV bug, and RFC 4180 answers it precisely.

The RFC 4180 quoting rules in plain English

RFC 4180 — published in 2005 and still the closest thing CSV has to a specification — sets out three rules that matter here:

  • Fields containing a comma, CRLF, or a double quote should be enclosed in double quotes.
  • Inside a quoted field, a literal double quote is escaped by doubling it (""), not by a backslash.
  • Spaces are part of the field and must not be trimmed.

So a field holding He said "hi", loudly is written as:

"He said ""hi"", loudly"

There is no backslash escaping in CSV. \" is two literal characters. A parser that treats \ as an escape character is inventing syntax.

Multi-line fields inside a single row

Rule 6 of the RFC allows a line break inside a quoted field. That means a CSV row is not the same thing as a text line — an address field with an embedded newline occupies three physical lines and one logical record. Any tool that reads the file line-by-line before parsing will split that record in half. Python's csv module documents this explicitly, which is why its docs insist you open files with newline=''.

Why "just split on commas" survives so long

It works on the first ten rows of every sample file. The failure only appears in production, when a support ticket description or a European address arrives with a comma in it — and it fails silently, shifting every subsequent column by one. The RFC itself is candid about the mess, noting that "due to lack of a single specification, there are considerable differences among implementations."

How to handle type inference: should "42" be a number or a string?

Every cell in a CSV is text. Deciding which cells become JSON numbers, booleans or nulls is where converters differ most.

When automatic typing helps

For exploratory work — feeding a chart, sanity-checking a dataset — automatic typing is what you want. "1250.50" as a JSON string means your sum concatenates instead of adding. Papa Parse calls this dynamicTyping and, per its documentation, deliberately leaves values above 2^53 as strings to avoid silent precision loss in IEEE-754 doubles.

When automatic typing corrupts your data

The classic casualties:

Value Naively typed Should be
01730 1730 "01730"
+44 20 7946 parse error / string "+44 20 7946"
3.0 3 "3.0" if a version
TRUE true depends on column

Zip codes, account numbers, SKUs, ISBNs, phone numbers and version strings are identifiers that happen to be made of digits. Arithmetic on them is meaningless; leading zeros are meaningful. The safe default for an import pipeline is: everything is a string unless a column is explicitly declared numeric.

Empty fields, nulls, and the NULL string

Three distinct things arrive as an empty cell: a genuine empty string, a missing value, and a database NULL that some exporter rendered as the literal text NULL. Pick one convention and document it. Python's csv.DictReader fills missing trailing fields with restval (default None), and Python 3.12 added QUOTE_NOTNULL and QUOTE_STRINGS so a writer can distinguish an empty string from None on the way out.

Delimiters, encodings, and CSVs that aren't comma-separated

Why European exports use semicolons

In locales where the decimal separator is a comma, 1.234,56 and a comma delimiter cannot coexist. Excel therefore exports with ; in those locales. The file is still called .csv. A converter that assumes commas returns one giant column per row. Good parsers sniff the delimiter — Papa Parse guesses from ,, \t, |, ; and the ASCII record/unit separators; Python ships a csv.Sniffer class that does the same job with an explicit warning that it is a heuristic.

The BOM that breaks your first key

Excel needs a UTF-8 byte order mark (U+FEFF) at the start of the file to reliably detect UTF-8. Without it, accented Latin, Cyrillic and CJK text often renders as mojibake. But if that BOM survives into your parser, the first header becomes "id" instead of "id" — and every lookup of row["id"] returns undefined. Strip it before parsing:

const clean = text.replace(/^/, "");
const rows = parseCsv(clean);

Papa Parse lists  among its forbidden delimiters for exactly this reason.

CRLF, LF, and files that have both

RFC 4180 specifies CRLF line endings and the text/csv media type inherits that from MIME. Real files arrive with LF, and files edited on two platforms arrive with both. Detect rather than assume; a stray \r at the end of the last column is a classic cause of a trailing-whitespace mismatch that no one can see in a diff.

How to convert CSV to JSON in Python, JavaScript and jq

Python: csv.DictReader plus json.dump

The standard library covers this in six lines, with no dependencies:

import csv, json

with open("in.csv", newline="",
          encoding="utf-8-sig") as f:
    rows = list(csv.DictReader(f))

with open("out.json", "w") as out:
    json.dump(rows, out, indent=2)

Two details matter. newline="" lets the csv module do its own newline handling so quoted multi-line fields survive. encoding="utf-8-sig" strips an Excel BOM if there is one and is harmless if there isn't.

JavaScript: File API in the browser

In a browser, File.text() gives you the contents without a server round trip:

const file = input.files[0];
const text = await file.text();
const json = csvToJson(text); // your parser

That's the whole reason browser-side conversion is possible at all: the file is read locally by the page, and nothing is uploaded.

Command line: jq for the reverse trip

Going JSON → CSV on the command line, jq handles the quoting correctly via @csv:

jq -r '(.[0] | keys_unsorted), \
  (.[] | [.[]]) | @csv' in.json > out.csv

@csv applies RFC-style quoting, so you don't hand-roll the escaping.

Privacy and safety when converting CSV files

Customer lists are the most-converted, least-considered files

The CSVs people convert are exports: user tables, order histories, mailing lists, payroll. Pasting one into a cloud converter transmits every row to a third party — a processing relationship most privacy policies require you to disclose, and one you probably haven't. Nothing about splitting a string on commas needs a server. Every tool in the iKit suite runs entirely in the browser for this reason.

CSV injection: the risk on the way back out

If your JSON eventually becomes a CSV that someone opens in Excel, sanitise it. OWASP documents CSV injection, where a cell beginning with =, +, -, @, tab, or a carriage return is interpreted by the spreadsheet as a formula. It is a real attack path when user-supplied names or notes end up in an exported report, and OWASP notes there is no single sanitisation strategy that is safe across every spreadsheet application.

Checking a converter is really client-side

Open DevTools, switch to the Network tab, and convert a file. If no request carries your data, the tool is doing what it claims. It's a ten-second test and worth running on any tool you feed real records to. Once the JSON is out, format and validate it before shipping it to an API, and if the destination is a spreadsheet rather than an endpoint, an SQL to Excel converter may be the shorter path.

References

Related on iKit

Related posts