Skip to main content

How to convert JSON to CSV (and handle nested data)

7 min read

Turn a JSON array into a spreadsheet-ready CSV, by hand, in JavaScript or Python, and the flattening decision that trips people up.

Converting JSON to CSV means turning an array of objects into rows and columns: each object becomes a row, and each key becomes a column header. The fastest way is a converter tool like our JSON to CSV converter, but you can also do it in a handful of lines of JavaScript or Python. The only part that takes real thought is flattening nested data, because CSV is flat and JSON often is not.

The shape of the problem

CSV is a grid: a fixed set of columns, one row per record. JSON is a tree: objects can contain other objects and arrays to any depth. So the clean case is an array of flat objects that all share the same keys. That maps to a table directly:

[
  { "id": 1, "name": "Ada",   "role": "admin" },
  { "id": 2, "name": "Linus", "role": "user"  }
]

id,name,role
1,Ada,admin
2,Linus,user

The header row comes from the object keys, and every object contributes one data row. Everything else in this guide is about getting messier data into that shape.

Method 1: an online converter

If you just need the file, paste your JSON into a converter and copy the result. Our JSON to CSV tool runs entirely in your browser, so your data never leaves your device, and it handles the header row, quoting, and escaping for you. This is the right choice for a one-off export or a quick check.

Method 2: JavaScript

When the conversion is part of a script or app, a small function does the job. The important detail is escaping: any value that contains a comma, a double quote, or a newline must be wrapped in double quotes, and any double quote inside it must be doubled.

function toCsv(rows) {
  if (rows.length === 0) return "";

  const headers = Object.keys(rows[0]);

  const escape = (value) => {
    const s = value == null ? "" : String(value);
    // Quote if the value contains a comma, quote, or newline.
    if (/[",\n]/.test(s)) {
      return '"' + s.replace(/"/g, '""') + '"';
    }
    return s;
  };

  const lines = [
    headers.join(","),
    ...rows.map((row) => headers.map((h) => escape(row[h])).join(",")),
  ];

  return lines.join("\n");
}

// const data = [{ id: 1, name: "Ada" }, { id: 2, name: "Linus" }];
// console.log(toCsv(data));

This assumes every object shares the first object’s keys. If your objects have differing keys, build the header from the union of all keys first, then fill missing values with an empty string.

Method 3: Python

Python’s standard library already knows how to write CSV, quoting and escaping included. csv.DictWriter is the direct fit for a list of dictionaries:

import csv, json

data = json.loads('[{"id": 1, "name": "Ada"}, {"id": 2, "name": "Linus"}]')

with open("out.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=data[0].keys())
    writer.writeheader()
    writer.writerows(data)

Passing newline="" when opening the file is important on Windows: it stops Python from turning each line ending into a doubled blank line.

Handling nested data

Real JSON often nests. Say each record has an address object:

{
  "id": 1,
  "name": "Ada",
  "address": { "city": "London", "zip": "EC1" },
  "tags": ["admin", "beta"]
}

A nested object is usually flattened into dot-notation columns, so address.city and address.zip become their own headers:

id,name,address.city,address.zip,tags
1,Ada,London,EC1,"admin, beta"

Arrays are the genuinely ambiguous case. You have two reasonable options, and which is right depends entirely on what will read the file:

  • Join into one cell. Combine the items into a single value like "admin, beta". Simple, and fine when the array is just a label list.
  • Explode into columns or rows. Give each item its own column (tags.0, tags.1) or repeat the record across multiple rows, one per item. Better when each item is a full record in its own right.

There is no universally correct choice, which is exactly why nested JSON does not convert “automatically” without you deciding this.

Escaping and spreadsheet gotchas

  • Commas, quotes, and newlines inside a value must be quoted, or the columns shift. Both snippets above (and any good tool) handle this.
  • Leading zeros in values like ZIP codes or IDs are often dropped when a spreadsheet reads the cell as a number. Keep them as text if they matter.
  • A leading =, +, or - can make Excel treat a cell as a formula. If your data can contain these, prefix the value or import as text to avoid formula injection.
  • Encoding. Save as UTF-8 so accented characters and symbols survive the trip into a spreadsheet.

For a quick, private conversion with the quoting and flattening already handled, paste your data into our free JSON to CSV converter. It runs in your browser, so nothing you convert is uploaded anywhere.

Frequently asked questions

How do I convert JSON to CSV?
Take an array of objects, use the object keys as the column headers, and write one row per object. The fastest way is a converter tool; you can also do it in a few lines of JavaScript or Python. The only tricky part is flattening nested objects and arrays into flat columns.
How do I convert JSON to CSV in JavaScript?
Collect the keys from your objects to form the header row, then map each object to a row of values. Wrap any value that contains a comma, quote, or newline in double quotes, and double any quote characters inside it. Join the values with commas and the rows with newlines.
How do I convert JSON to CSV in Python?
Use the built-in csv module. csv.DictWriter takes your list of column names as fieldnames, writes the header with writeheader(), and writes each dictionary as a row with writerows(). It handles quoting and escaping for you.
How do I convert nested JSON to CSV?
Flatten nested objects into dot-notation columns, so user.name becomes a column called 'user.name'. For arrays, either join the items into a single cell or explode them across several columns or rows. There is no single correct answer; it depends on what will read the CSV.