How to Convert JSON to CSV: Complete Guide
JSON and CSV are the two most common data exchange formats, but they serve very different purposes. JSON (JavaScript Object Notation) handles complex nested structures and is the default format for APIs and web services. CSV (Comma-Separated Values) is flat, tabular, and universally supported by Excel, Google Sheets, databases, and data pipelines. Converting JSON to CSV is one of the most common data tasks β whether you are exporting API data to a spreadsheet, importing records into a database, or preparing reports for stakeholders. This guide covers the simple case, the hard parts (nested objects, inconsistent keys), code examples in JavaScript, Python, Go, and the command line, plus common pitfalls. For quick conversions, try our JSON to CSV Converter β it runs entirely in your browser.
When Do You Need This?
- Exporting API data to Excel β stakeholders want spreadsheets, not JSON files
- Database imports β many databases accept CSV for bulk inserts
- Data analysis β tools like pandas, R, and SQL work better with tabular data
- Reporting β CSV is the lingua franca of business data
- Log processing β converting structured JSON logs to CSV for grep/awk workflows
The Simple Case: Flat Array of Objects
The easiest scenario β an array where every object has the same keys:
[
{ "name": "Alice", "age": 30, "city": "Berlin" },
{ "name": "Bob", "age": 25, "city": "Tokyo" },
{ "name": "Carol", "age": 35, "city": "London" }
]
Becomes:
name,age,city
Alice,30,Berlin
Bob,25,Tokyo
Carol,35,London
The keys become column headers, and each object becomes a row. This is what most tools and libraries handle automatically.
The Hard Part: Nested Objects
Real-world JSON is rarely flat. Consider:
[
{
"id": 1,
"name": "Alice",
"address": {
"street": "123 Main St",
"city": "Berlin",
"country": "DE"
},
"tags": ["admin", "user"]
}
]
There are several strategies for handling this:
Dot notation flattening
Flatten nested keys with dots: address.street, address.city, address.country. Arrays become tags.0, tags.1 or a joined string "admin,user".
id,name,address.street,address.city,address.country,tags
1,Alice,123 Main St,Berlin,DE,"admin,user"
JSON string columns
Keep nested values as JSON strings in the CSV cell:
id,name,address,tags
1,Alice,"{""street"":""123 Main St"",""city"":""Berlin""}","[""admin"",""user""]"
This preserves data structure but makes the CSV harder to work with in spreadsheets.
Extract specific fields
Only pick the fields you need β often the most practical approach:
id,name,city,country
1,Alice,Berlin,DE
Code Examples
JavaScript (Node.js)
// Simple flat conversion
function jsonToCsv(data) {
if (!data.length) return '';
const headers = Object.keys(data[0]);
const rows = data.map(obj =>
headers.map(h => {
const val = obj[h] ?? '';
const str = String(val);
return str.includes(',') || str.includes('"') || str.includes('\n')
? `"${str.replace(/"/g, '""')}"`
: str;
}).join(',')
);
return [headers.join(','), ...rows].join('\n');
}
// With nested object flattening
function flatten(obj, prefix = '') {
return Object.entries(obj).reduce((acc, [key, val]) => {
const newKey = prefix ? `${prefix}.${key}` : key;
if (val && typeof val === 'object' && !Array.isArray(val)) {
Object.assign(acc, flatten(val, newKey));
} else {
acc[newKey] = Array.isArray(val) ? val.join('; ') : val;
}
return acc;
}, {});
}
const flat = data.map(item => flatten(item));
console.log(jsonToCsv(flat));
Python
import csv
import json
import io
# Simple: using csv.DictWriter
def json_to_csv(data):
if not data:
return ""
output = io.StringIO()
writer = csv.DictWriter(output, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
return output.getvalue()
# With pandas (handles nested data, missing keys, type conversion)
import pandas as pd
df = pd.json_normalize(data) # Automatically flattens nested objects
df.to_csv("output.csv", index=False)
# From a JSON file
with open("data.json") as f:
data = json.load(f)
df = pd.json_normalize(data)
df.to_csv("output.csv", index=False)
pd.json_normalize() is particularly powerful β it automatically flattens nested objects using dot notation and handles missing keys gracefully.
Command Line with jq
jq is the Swiss army knife for JSON on the command line:
# Flat array of objects β CSV
cat data.json | jq -r '
(.[0] | keys_unsorted) as $keys |
($keys | @csv),
(.[] | [.[$keys[]]] | @csv)
'
# Extract specific fields
cat data.json | jq -r '.[] | [.name, .age, .city] | @csv'
# From an API directly
curl -s "https://api.example.com/users" | jq -r '
["name","email","role"],
(.[] | [.name, .email, .role]) | @csv
' > users.csv
Go
import (
"encoding/csv"
"encoding/json"
"os"
)
// Assuming flat []map[string]interface{}
func jsonToCSV(data []map[string]interface{}, w *os.File) {
writer := csv.NewWriter(w)
defer writer.Flush()
// Headers from first record
headers := make([]string, 0)
for k := range data[0] {
headers = append(headers, k)
}
writer.Write(headers)
// Rows
for _, record := range data {
row := make([]string, len(headers))
for i, h := range headers {
row[i] = fmt.Sprintf("%v", record[h])
}
writer.Write(row)
}
}
Common Pitfalls
Commas and quotes in values
CSV values containing commas, double quotes, or newlines must be wrapped in double quotes. Double quotes inside a value must be escaped as "":
name,description
"Smith, John","He said ""hello"""
Most libraries handle this automatically. If youβre building a converter manually, donβt forget this step β itβs the #1 source of broken CSV files.
Inconsistent keys across objects
If not every JSON object has the same keys, you need to collect all unique keys first and fill in empty values:
[
{ "name": "Alice", "age": 30 },
{ "name": "Bob", "email": "bob@example.com" }
]
Should produce:
name,age,email
Alice,30,
Bob,,bob@example.com
Encoding issues
JSON is always UTF-8. CSV files opened in Excel may need a BOM (Byte Order Mark) to display Unicode correctly:
with open("output.csv", "w", encoding="utf-8-sig") as f:
# utf-8-sig adds the BOM automatically
writer = csv.writer(f)
...
Large files and memory
Loading a 500 MB JSON file into memory to convert it will likely crash. For large files, use streaming parsers:
- Python:
ijsonfor streaming JSON parsing +csv.writerfor streaming output - Node.js:
JSONStreamorstream-json - Command line:
jqhandles large files efficiently with streaming
CSV to JSON: The Reverse
Going the other direction is often needed too. The key decision is whether the result should be an array of objects (most common) or an array of arrays:
import csv, json
with open("data.csv") as f:
reader = csv.DictReader(f)
data = list(reader)
with open("data.json", "w") as f:
json.dump(data, f, indent=2)
Try It Yourself
Convert JSON to CSV instantly in your browser with our JSON to CSV Converter. It handles nested objects, missing keys, and proper CSV escaping automatically.
You can also use the JSON Formatter to clean up your JSON before conversion, or the JSON Validator to check for syntax errors.
For converting the other direction, check out the YAML to JSON Converter for configuration files.
Further Reading
- RFC 4180 β Common Format and MIME Type for CSV Files
- jq Manual β Command-line JSON processor
- pandas.json_normalize β Flatten nested JSON in Python
- MDN: JSON β JavaScript JSON reference