Why Convert JSON to CSV?

JSON is the standard data format for APIs and web applications, but it is not the best format for every task. When you need to analyze data in a spreadsheet, import records into a database, or share data with non-technical stakeholders, CSV (Comma-Separated Values) is often the better choice.

CSV files open natively in Excel, Google Sheets, and every data analysis tool. They are flat, tabular, and universally supported. Converting JSON to CSV bridges the gap between modern APIs and traditional data workflows.

Basic Conversion: Flat Objects

The simplest case is a JSON array of flat objects — objects with no nesting, where every value is a string, number, boolean, or null. Each object becomes a row, and the object keys become column headers.

Given this JSON input:

[
  { "name": "Alice", "age": 30, "city": "New York" },
  { "name": "Bob", "age": 25, "city": "London" },
  { "name": "Charlie", "age": 35, "city": "Tokyo" }
]

The CSV output is:

name,age,city
Alice,30,New York
Bob,25,London
Charlie,35,Tokyo

The first row contains the headers (the union of all keys across all objects), and each subsequent row contains the corresponding values. If an object is missing a key that other objects have, the cell is left empty.

Handling Nested Objects

Real-world JSON often contains nested objects. For example, an API response might include an address object with city, state, and zip fields. Since CSV is a flat format, you need to flatten these nested structures.

The standard approach is dot notation: concatenate parent and child keys with a dot separator. An object like {"address": {"city": "NYC", "zip": "10001"}} becomes two columns: address.city and address.zip.

Example input:

[
  {
    "name": "Alice",
    "address": { "city": "NYC", "state": "NY" }
  },
  {
    "name": "Bob",
    "address": { "city": "London", "state": null }
  }
]

Flattened CSV output:

name,address.city,address.state
Alice,NYC,NY
Bob,London,

This approach works recursively for any depth of nesting. A key like user.address.street.line1 is perfectly valid as a CSV column header.

Handling Arrays Within Objects

Arrays within objects present a different challenge. A field like "tags": ["dev", "lead", "remote"] cannot be split into separate columns because the number of elements varies across rows.

The most common solution is to join array elements with a delimiter — typically a semicolon (;) since commas would conflict with the CSV format. The example above becomes dev;lead;remote in a single CSV cell.

If the array contains objects rather than primitives, you can either flatten each object into a JSON string or, if the structure is consistent, create numbered columns like items[0].name, items[1].name. The semicolon-join approach is simpler and works well for most use cases.

Edge Cases and Pitfalls

Several edge cases can trip you up when converting JSON to CSV:

Converting Programmatically

In JavaScript, you can convert JSON to CSV in a few lines. Extract the headers from all objects, then map each object to a row of comma-separated values:

function jsonToCSV(data) {
  const headers = [...new Set(data.flatMap(Object.keys))];
  const rows = data.map(obj =>
    headers.map(h => {
      const val = obj[h] ?? '';
      const str = String(val);
      return str.includes(',') || str.includes('"')
        ? '"' + str.replace(/"/g, '""') + '"'
        : str;
    }).join(',')
  );
  return [headers.join(','), ...rows].join('\n');
}

In Python, the built-in csv module handles escaping automatically:

import csv, io, json

def json_to_csv(data):
    headers = list({k for obj in data for k in obj})
    output = io.StringIO()
    writer = csv.DictWriter(output, fieldnames=headers)
    writer.writeheader()
    writer.writerows(data)
    return output.getvalue()

For quick, one-off conversions without writing code, use an online tool like ToolPlex's JSON Converter — paste your JSON and download the CSV instantly.