{ }jsonkitOpen

JSON vs CSV: how and when to convert between them

7 min read · updated 2026-07-12

JSON vs CSV comes down to shape. CSV is a flat grid of rows and columns. JSON is a nested tree of objects, arrays and typed values. Both are common for moving data between systems, and that difference in shape is why converting between them is harder than it looks.

This guide compares the two, shows when each one fits, and covers the hard part: flattening nested JSON into CSV columns and getting types back on the return trip. To just convert a file, use the JSON to CSV and CSV to JSON converters.

JSON vs CSV at a glance

Both formats are plain text that people can read, but they answer different questions. CSV answers "what does this table look like?" JSON answers "what is the shape of this object?" Pick the wrong one and you fight the format for as long as the file exists.

AspectCSVJSON
StructureFlat rows and columnsNested objects and arrays
TypesNone, everything is textstring, number, boolean, null, object, array
RepetitionCompact, no repeated keysKeys repeat on every object
NestingNot supportedBuilt in
ToolingExcel, Sheets, pandas, SQL importsAPIs, config, JS and most languages
StreamingEasy, one line at a timeNeeds a streaming parser or NDJSON

A simple rule: if a non-developer will open the file, use CSV. If a program will read it over HTTP, use JSON. For the same comparison against other formats, see JSON vs YAML and JSON vs XML.

When to use CSV

CSV works best when your data is truly tabular: a list of records where every row has the same fields. Spreadsheets and analytics tools all read it. For large flat datasets it is much smaller than JSON, because column names appear once in the header instead of on every record.

  • Exports meant to open in Excel or Google Sheets
  • Bulk imports into a SQL database or data warehouse
  • Analytics and data-science pipelines (pandas, R, DuckDB)
  • Large uniform datasets where per-row key repetition wastes space
  • Handing data to non-technical stakeholders

CSV struggles as soon as your data has optional fields, nested structures or arrays. You end up with sparse columns, made-up naming schemes, or cells packed with delimiters.

When to use JSON

Use JSON when structure and types matter. It keeps the difference between the number 42 and the string "42", between false and "false", and between a missing field and an empty one. It handles nesting and arrays without encoding tricks, which is why web APIs and config files use it.

  • REST and GraphQL request and response bodies
  • Configuration files and application state
  • Documents with nested or variable structure
  • Data where types must survive a round trip
  • Anything read directly by JavaScript or most modern languages

The hard part: flattening nested JSON

CSV has no nesting, so converting JSON to CSV means fitting a tree onto a grid. The usual approach joins nested keys into one column name with a path convention. Dot notation is the most common. Take this nested record:

nested source: one user with a nested address and a tags arrayjson
[
  {
    "id": 1,
    "name": "Ada Lovelace",
    "active": true,
    "address": { "city": "London", "zip": "WC1" },
    "tags": ["admin", "beta"]
  }
]

With dot notation for objects and index notation for the array, it becomes a single row. The nested address.city key and each tag position get their own column:

the same record flattened to CSVtext
id,name,active,address.city,address.zip,tags.0,tags.1
1,Ada Lovelace,true,London,WC1,admin,beta

Handling arrays

Arrays are the hardest part, because their length varies between records. You have three options, each with a trade-off:

  1. Index into columns (tags.0, tags.1). This is simple, but the column set changes with array length, so the output gets sparse or ragged.
  2. Join into one cell (tags = "admin;beta"). The column set stays fixed, but you must pick a separator that will not collide with your delimiter, and you lose the array structure.
  3. Explode into multiple rows, one per array element, repeating the parent fields. Analysts prefer this tidy-data layout, but it changes the row count and repeats data.
JSON to CSVPaste nested JSON and get flattened CSV with dot-path column names, your choice of delimiter and correct quoting. It runs in your browser.→

Converting CSV back to JSON and inferring types

The reverse direction has the opposite problem. CSV values are all strings, so a basic parser returns every field as text. Rebuilding JSON takes two jobs: rebuilding the nesting from the column names, and guessing the intended type of each value.

minimal type inference when parsing CSV cellsjs
function inferType(value) {
  if (value === "") return null
  if (value === "true") return true
  if (value === "false") return false
  // Only treat as a number if it round-trips exactly,
  // so "007" and "1e999" stay strings.
  const num = Number(value)
  if (!Number.isNaN(num) && String(num) === value) return num
  return value
}

console.log(inferType("42"))    // 42     (number)
console.log(inferType("007"))   // "007"  (string, leading zero preserved)
console.log(inferType("true"))  // true   (boolean)
console.log(inferType(""))      // null

Rebuilding the nesting reverses the flattening. Split each header on the dot, then walk the path and create objects as you go, or arrays for numeric segments.

rebuild nested objects from dot-notation headersjs
function setPath(target, path, value) {
  const keys = path.split(".")
  let node = target
  keys.forEach((key, i) => {
    if (i === keys.length - 1) {
      node[key] = value
      return
    }
    // Next segment numeric? create an array, else an object.
    if (node[key] === undefined) {
      node[key] = /^\d+$/.test(keys[i + 1]) ? [] : {}
    }
    node = node[key]
  })
  return target
}

const row = { "address.city": "London", "tags.0": "admin" }
let out = {}
for (const [header, value] of Object.entries(row)) {
  setPath(out, header, value)
}
// out => { address: { city: "London" }, tags: ["admin"] }

Delimiters, headers and escaping

Most CSV problems in practice are not about structure. They come from the mechanics of the format. The common standard is RFC 4180, and following it prevents most import failures.

Delimiters

The C in CSV means comma. Semicolons are common in locales where the comma is the decimal separator, and tabs (TSV) avoid the problem altogether. Whatever you pick, the writer and the parser must agree. A file written with semicolons but read as comma-delimited collapses into one column.

Headers

The first row is usually a header that names each column. The spec makes it optional, but JSON conversion needs it, because the header supplies the object keys. Keep headers stable and unique. Duplicate column names make the target object ambiguous.

Quoting and escaping

Wrap any field that contains the delimiter, a double quote or a line break in double quotes. Escape a double quote inside the field by doubling it. People get this rule wrong by hand more than any other:

a value with a comma, a quote and a newline, correctly quotedtext
id,note
1,"Says ""hi"", then, a pause
and a newline"

A practical conversion workflow

Put together, a reliable round trip looks like this:

  1. Check the JSON shape first. A flat array of uniform objects converts cleanly. Nested data needs a flattening decision.
  2. Choose an array strategy up front (index, join or explode) and use it across the whole dataset.
  3. Pick a delimiter that will not collide with your data, and always write a header row.
  4. Convert, then spot-check identifier columns for unwanted type changes, such as lost leading zeros or long IDs read as numbers.
  5. If the receiving system is strict, validate the rebuilt JSON against a schema.

Both converters run in your browser, so nothing is uploaded. Use JSON to CSV for exports. It flattens nested objects into dot-path columns and quotes values per RFC 4180. Use CSV to JSON for imports. It can infer numbers and booleans, and it keeps dot-path headers as flat keys, so rebuild the nesting in code if you need it.

Frequently asked questions

Can CSV represent nested JSON?

Not directly. CSV is a flat grid, so nested JSON must be flattened first. The usual way is to join nested keys into column names with dot notation (address.city). Arrays are indexed into columns, joined into one cell, or exploded into multiple rows. The structure survives by convention, not through the format.

Why do my numbers or IDs change when converting CSV to JSON?

CSV has no types, so parsers guess. Aggressive type inference turns "007" into 7, "01234" into 1234 and "1e5" into 100000. Keep identifier and code columns as strings. Prefer a parser that only treats a value as a number when it round-trips exactly (String(Number(value)) === value).

Which is smaller, JSON or CSV?

For large uniform datasets, CSV is usually much smaller, because column names appear once in the header instead of on every JSON object. For small or deeply nested data the difference is minor, and JSON's structure is worth the extra bytes.

What delimiter should I use for CSV?

Comma is the default and works almost everywhere. Use semicolons in locales where the comma is a decimal separator, or tabs (TSV) to avoid delimiter collisions. The one hard rule: the program that writes the file and the one that reads it must use the same delimiter.

How do I handle commas or quotes inside a CSV value?

Follow RFC 4180. Wrap any field that contains the delimiter, a double quote or a newline in double quotes, and escape double quotes inside it by doubling them (""). Do not join values on commas yourself. Use a library or tool that implements this quoting.

Is it safe to convert JSON to CSV online?

It depends on the tool. JsonKit's converters run in your browser, so your data is never uploaded. Avoid pasting sensitive data into tools that send it to a server.