JSON to CSV Basics
CSV (Comma-Separated Values) is a flat tabular format, while JSON supports nested structures. Converting requires:
Key Concepts:
- Flattening - Nested objects become dot-notation columns
- Arrays - Can be stringified or expanded to multiple rows
- Headers - Generated from JSON keys
- Escaping - Values with commas/quotes need special handling
Best Practices:
- Use arrays of objects with consistent keys
- Flatten deeply nested structures before conversion
- Handle null/undefined values explicitly
- Quote fields containing commas or newlines
Convert JSON to CSV in JavaScript
Build a robust JSON to CSV converter:
// Simple JSON array to CSV
function jsonToCsv(jsonArray) {
if (!jsonArray.length) return '';
// Get headers from first object
const headers = Object.keys(jsonArray[0]);
// Create CSV rows
const rows = jsonArray.map(obj =>
headers.map(header => {
const value = obj[header];
// Handle null, undefined, and escape quotes
if (value === null || value === undefined) return '';
const str = String(value);
// Escape quotes and wrap if contains comma/newline/quote
if (str.includes(',') || str.includes('\n') || str.includes('"')) {
return `"${str.replace(/"/g, '""')}"`;
}
return str;
}).join(',')
);
return [headers.join(','), ...rows].join('\n');
}
// Usage
const users = [
{ id: 1, name: "John Doe", email: "john@example.com" },
{ id: 2, name: "Jane Smith", email: "jane@example.com" }
];
console.log(jsonToCsv(users));
// id,name,email
// 1,John Doe,john@example.com
// 2,Jane Smith,jane@example.com
// Handle nested objects with flattening
function flattenObject(obj, prefix = '') {
return Object.keys(obj).reduce((acc, key) => {
const newKey = prefix ? `${prefix}.${key}` : key;
if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
Object.assign(acc, flattenObject(obj[key], newKey));
} else {
acc[newKey] = Array.isArray(obj[key]) ? JSON.stringify(obj[key]) : obj[key];
}
return acc;
}, {});
}
// Flatten then convert
const nested = [
{ user: { name: "John", email: "john@example.com" }, orders: 5 }
];
const flattened = nested.map(flattenObject);
console.log(jsonToCsv(flattened));
// user.name,user.email,orders
// John,john@example.com,5Convert JSON to CSV in Python
Python's csv module handles CSV properly:
import csv
import json
from io import StringIO
def json_to_csv(json_array):
if not json_array:
return ""
output = StringIO()
writer = csv.DictWriter(output, fieldnames=json_array[0].keys())
writer.writeheader()
writer.writerows(json_array)
return output.getvalue()
# Usage
users = [
{"id": 1, "name": "John Doe", "email": "john@example.com"},
{"id": 2, "name": "Jane Smith", "email": "jane@example.com"}
]
print(json_to_csv(users))
# Using pandas (more powerful)
import pandas as pd
# JSON array to CSV
df = pd.DataFrame(users)
df.to_csv("users.csv", index=False)
# Flatten nested JSON
def flatten_dict(d, parent_key='', sep='.'):
items = []
for k, v in d.items():
new_key = f"{parent_key}{sep}{k}" if parent_key else k
if isinstance(v, dict):
items.extend(flatten_dict(v, new_key, sep).items())
else:
items.append((new_key, v))
return dict(items)
nested_data = [
{"user": {"name": "John", "email": "john@example.com"}, "orders": 5}
]
flat_data = [flatten_dict(item) for item in nested_data]
df = pd.DataFrame(flat_data)
df.to_csv("output.csv", index=False)
# Read JSON file, write CSV
df = pd.read_json("data.json")
df.to_csv("data.csv", index=False)Command Line Conversion
Convert JSON to CSV using CLI tools:
# Using jq + miller (mlr)
# Install: brew install jq miller
cat data.json | jq -r '.[] | [.id, .name, .email] | @csv' > output.csv
# With headers
echo "id,name,email" > output.csv
cat data.json | jq -r '.[] | [.id, .name, .email] | @csv' >> output.csv
# Using miller (handles nested JSON)
mlr --json --ocsv cat data.json > output.csv
# Using csvkit (Python-based)
# pip install csvkit
in2csv data.json > output.csv
# Using Node.js json2csv
# npm install -g json2csv
json2csv -i data.json -o output.csv
# Convert with specific fields
json2csv -i data.json -f id,name,email -o output.csv
# Flatten nested objects
json2csv -i data.json --flatten-objects -o output.csvHandle Complex JSON Structures
Strategies for converting complex nested JSON:
// Array values: stringify or expand
const withArrays = [
{ id: 1, name: "John", tags: ["developer", "nodejs"] },
{ id: 2, name: "Jane", tags: ["designer", "ui"] }
];
// Option 1: Stringify arrays
// tags column: ["developer","nodejs"]
// Option 2: Join array values
const processed = withArrays.map(item => ({
...item,
tags: item.tags.join('; ')
}));
// tags column: developer; nodejs
// Option 3: Expand to columns
const expanded = withArrays.map(item => ({
id: item.id,
name: item.name,
tag1: item.tags[0] || '',
tag2: item.tags[1] || ''
}));
// Handle missing keys across objects
const inconsistent = [
{ id: 1, name: "John" },
{ id: 2, email: "jane@example.com" }
];
// Collect all keys
const allKeys = [...new Set(inconsistent.flatMap(Object.keys))];
// Normalize objects
const normalized = inconsistent.map(obj =>
Object.fromEntries(allKeys.map(key => [key, obj[key] ?? '']))
);
// Deep nested flattening with path
function deepFlatten(obj, path = []) {
return Object.entries(obj).reduce((acc, [key, value]) => {
const newPath = [...path, key];
if (value && typeof value === 'object' && !Array.isArray(value)) {
Object.assign(acc, deepFlatten(value, newPath));
} else {
acc[newPath.join('.')] = value;
}
return acc;
}, {});
}Frequently Asked Questions
How are nested objects handled?
Nested objects are flattened using dot notation. {user: {name: 'John'}} becomes a 'user.name' column. Arrays can be stringified or expanded.
What if JSON objects have different keys?
Collect all unique keys across all objects to create headers. Missing values become empty cells in the CSV.
How do I handle special characters?
Fields containing commas, quotes, or newlines should be wrapped in double quotes. Quotes within fields are escaped by doubling them.
Can I choose which fields to export?
Yes! Filter the object keys before conversion, or use tools like json2csv with the -f flag to specify fields.