Python

Convert JSON to CSV in Python: Complete Guide with Examples

Convert JSON to CSV and back using Python's json, csv, and pandas libraries. Includes nested JSON handling, error handling, and production-ready code examples.

By InventiveHQ Team

To convert JSON to CSV in Python, read the JSON with json.load(), use the keys of the first object as your header row, and write the rows with csv.DictWriter โ€” no third-party library required. The minimal round-trip is four lines: data = json.load(open('in.json')), w = csv.DictWriter(open('out.csv', 'w', newline=''), fieldnames=data[0].keys()), w.writeheader(), w.writerows(data). Going the other way (csv.DictReader โ†’ json.dump) is even simpler, but it loses type information, because CSV stores everything as text. Both json and csv ship with Python 3, so nothing needs to be installed.

That is the summary an AI overview will give you. What it can't show you is what actually breaks in production: inconsistent keys that make DictWriter throw, nested objects that CSV cannot represent, numbers that silently become strings on the way back, and Windows encoding defaults that mangle every accented name. This guide handles all of those. Start by trying the conversion live below, then use the annotated, edge-case-hardened code that follows.

Loading interactive tool...

This converter runs entirely in your browser โ€” nothing is uploaded. Use it for one-off conversions, or to confirm your Python output matches the expected result.

Prerequisites and Setup

Before we begin, make sure you have:

  • Python 3.6 or higher installed on your system
  • Basic understanding of Python syntax and data structures
  • A text editor or IDE for writing Python code
  • Basic familiarity with JSON and CSV data formats

The good news is that Python includes all the libraries we need for this tutorial in its standard library, so no additional installations are required.

๐Ÿ’ก Pro Tip: If you're new to JSON, check out our comprehensive guide on What is JSON? to understand the basics of this popular data format before diving into conversion techniques.

Understanding When to Convert Between Formats

There are several common scenarios where format conversion becomes necessary:

JSON to CSV Conversion

  • API Data Analysis: When you retrieve data from REST APIs (typically in JSON format) and need to analyze it in Excel or Google Sheets
  • Data Migration: Moving data from NoSQL databases to relational databases or data warehouses
  • Reporting: Creating reports and dashboards from API responses
  • PowerShell Integration: Working with PowerShell scripts that handle CSV files more efficiently than JSON

CSV to JSON Conversion

  • API Integration: Sending data to web APIs that expect JSON payloads
  • Web Development: Converting spreadsheet data for use in web applications
  • Configuration Files: Creating configuration files from tabular data
  • Database Imports: Preparing data for NoSQL databases like MongoDB

Which Approach Should You Use?

There are three sensible ways to convert between JSON and CSV. They are not interchangeable โ€” the right one depends on file size, whether you can add dependencies, and how much reshaping you need.

ApproachBest forMemory profileNested dataDependenciesWhen to pick it
csv + json stdlibServers, scripts, CI, large filesLow (can stream)Manual flatteningNoneDefault choice โ€” no install, full control over quoting and types
pandasAnalysis, quick one-liners, reshapingHigh (loads all to RAM)json_normalize()pip install pandasYou already use pandas or need to filter/pivot on the way through
Browser tool (above)One-off conversions, verifying outputN/A (client-side)Auto-flattenedNoneYou want a result in seconds without writing or running code

The single most important distinction: the stdlib csv module can process files larger than your RAM by writing row-by-row, while pandas loads the entire dataset into memory before it writes anything. For a 50 MB export that difference is irrelevant; for a 5 GB one it is the difference between a working script and a MemoryError.

The Round Trip Is Not Lossless

Before writing any code, understand the one fact that trips up every beginner: JSON โ†’ CSV โ†’ JSON does not always give you back what you started with. JSON has types (numbers, booleans, null, nested objects); CSV has only text. The diagram below shows what survives the trip and what you have to rebuild by hand.

JSON to CSV round-trip type loss JSON carries typed values into CSV, where everything becomes text; converting back requires manually re-casting numbers and booleans. JSON (typed) "id": 42 "paid": true "score": null "name": "Ada" "tags": [ ... ] number / bool / null to CSV CSV (all text) id,paid,score,name "42" "true" "" "Ada" every field is a string back to JSON manual re-cast JSON again 42 "true" ? "" ? "Ada" bool + null must be rebuilt by you

Types are lost at the CSV boundary โ€” casting back is your job, not the format's.

How to Convert JSON to CSV

Converting JSON to CSV requires understanding the structure of your JSON data. This tutorial works best with JSON arrays containing objects with consistent key-value pairs. Let's start with a practical example.

Sample Data Setup

First, let's create a sample JSON file that represents customer data. Save this as customers.json:

[
  {
    "customer_id": 1,
    "name": "Alice Johnson",
    "email": "[[email protected]](/cdn-cgi/l/email-protection)",
    "city": "San Francisco",
    "state": "CA",
    "purchase_amount": 1250.50
  },
  {
    "customer_id": 2,
    "name": "Bob Smith",
    "email": "[[email protected]](/cdn-cgi/l/email-protection)",
    "city": "Austin",
    "state": "TX",
    "purchase_amount": 825.75
  },
  {
    "customer_id": 3,
    "name": "Carol Davis",
    "email": "[[email protected]](/cdn-cgi/l/email-protection)",
    "city": "Miami",
    "state": "FL",
    "purchase_amount": 2100.00
  },
  {
    "customer_id": 4,
    "name": "David Wilson",
    "email": "[[email protected]](/cdn-cgi/l/email-protection)",
    "city": "Seattle",
    "state": "WA",
    "purchase_amount": 675.25
  }
]

Basic JSON to CSV Conversion

Here's a complete Python script that converts our JSON data to CSV format:

import json
import csv

def json_to_csv(json_file_path, csv_file_path):
    """
    Convert a JSON file to CSV format.

    Args:
        json_file_path (str): Path to the input JSON file
        csv_file_path (str): Path to the output CSV file
    """
    try:
        # Read the JSON file
        with open(json_file_path, 'r', encoding='utf-8') as json_file:
            data = json.load(json_file)

        # Handle case where JSON is not a list
        if not isinstance(data, list):
            print("Error: JSON data must be a list of objects")
            return False

        # Handle empty data
        if not data:
            print("Warning: JSON file is empty")
            return False

        # Extract headers from the first object
        headers = list(data[0].keys())

        # Write to CSV file
        with open(csv_file_path, 'w', newline='', encoding='utf-8') as csv_file:
            writer = csv.DictWriter(csv_file, fieldnames=headers)

            # Write header row
            writer.writeheader()

            # Write data rows
            for row in data:
                writer.writerow(row)

        print(f"Successfully converted {json_file_path} to {csv_file_path}")
        return True

    except FileNotFoundError:
        print(f"Error: File {json_file_path} not found")
        return False
    except json.JSONDecodeError as e:
        print(f"Error: Invalid JSON format - {e}")
        return False
    except Exception as e:
        print(f"Error: {e}")
        return False

# Usage example
if __name__ == "__main__":
    json_to_csv('customers.json', 'customers.csv')

Running this script will create a CSV file with the following structure:

customer_id,name,email,city,state,purchase_amount
1,Alice Johnson,[[email protected]](/cdn-cgi/l/email-protection),San Francisco,CA,1250.5
2,Bob Smith,[[email protected]](/cdn-cgi/l/email-protection),Austin,TX,825.75
3,Carol Davis,[[email protected]](/cdn-cgi/l/email-protection),Miami,FL,2100.0
4,David Wilson,[[email protected]](/cdn-cgi/l/email-protection),Seattle,WA,675.25
Advertisement

How to Convert CSV to JSON

Converting CSV to JSON is typically more straightforward than the reverse process because CSV data has a predictable structure. Let's create a robust function that handles various edge cases.

import json
import csv

def csv_to_json(csv_file_path, json_file_path, indent=2):
    """
    Convert a CSV file to JSON format.

    Args:
        csv_file_path (str): Path to the input CSV file
        json_file_path (str): Path to the output JSON file
        indent (int): Number of spaces for JSON indentation (default: 2)
    """
    try:
        data = []

        # Read CSV file
        with open(csv_file_path, 'r', encoding='utf-8') as csv_file:
            csv_reader = csv.DictReader(csv_file)

            # Convert each row to a dictionary
            for row in csv_reader:
                # Convert numeric strings to appropriate data types
                converted_row = {}
                for key, value in row.items():
                    # Try to convert to int or float if possible
                    if value.isdigit():
                        converted_row[key] = int(value)
                    else:
                        try:
                            converted_row[key] = float(value)
                        except ValueError:
                            # Keep as string if conversion fails
                            converted_row[key] = value

                data.append(converted_row)

        # Handle empty CSV
        if not data:
            print("Warning: CSV file is empty or has no data rows")
            return False

        # Write JSON file
        with open(json_file_path, 'w', encoding='utf-8') as json_file:
            json.dump(data, json_file, indent=indent, ensure_ascii=False)

        print(f"Successfully converted {csv_file_path} to {json_file_path}")
        print(f"Converted {len(data)} records")
        return True

    except FileNotFoundError:
        print(f"Error: File {csv_file_path} not found")
        return False
    except csv.Error as e:
        print(f"Error: CSV parsing error - {e}")
        return False
    except Exception as e:
        print(f"Error: {e}")
        return False

# Usage example
if __name__ == "__main__":
    csv_to_json('customers.csv', 'customers_converted.json')

This script will produce a well-formatted JSON file with proper data types:

[
  {
    "customer_id": 1,
    "name": "Alice Johnson",
    "email": "[[email protected]](/cdn-cgi/l/email-protection)",
    "city": "San Francisco",
    "state": "CA",
    "purchase_amount": 1250.5
  },
  {
    "customer_id": 2,
    "name": "Bob Smith",
    "email": "[[email protected]](/cdn-cgi/l/email-protection)",
    "city": "Austin",
    "state": "TX",
    "purchase_amount": 825.75
  }
]

Advanced Features and Edge Cases

Handling Nested JSON Objects

Converting nested JSON structures requires flattening the data. Here's an enhanced version that handles nested objects:

def flatten_json(nested_json, separator='_'):
    """
    Flatten a nested JSON object.

    Args:
        nested_json (dict): The nested JSON object
        separator (str): Character to separate nested keys

    Returns:
        dict: Flattened dictionary
    """
    def _flatten(obj, parent_key=''):
        items = []
        if isinstance(obj, dict):
            for key, value in obj.items():
                new_key = f"{parent_key}{separator}{key}" if parent_key else key
                items.extend(_flatten(value, new_key).items())
        elif isinstance(obj, list):
            for i, value in enumerate(obj):
                new_key = f"{parent_key}{separator}{i}" if parent_key else str(i)
                items.extend(_flatten(value, new_key).items())
        else:
            return {parent_key: obj}
        return dict(items)

    return _flatten(nested_json)

def json_to_csv_advanced(json_file_path, csv_file_path):
    """
    Convert JSON with nested objects to CSV.
    """
    try:
        with open(json_file_path, 'r', encoding='utf-8') as json_file:
            data = json.load(json_file)

        if not isinstance(data, list):
            data = [data]  # Convert single object to list

        # Flatten all objects
        flattened_data = [flatten_json(obj) for obj in data]

        # Get all unique keys
        all_keys = set()
        for obj in flattened_data:
            all_keys.update(obj.keys())

        # Write to CSV
        with open(csv_file_path, 'w', newline='', encoding='utf-8') as csv_file:
            writer = csv.DictWriter(csv_file, fieldnames=sorted(all_keys))
            writer.writeheader()

            for obj in flattened_data:
                writer.writerow(obj)

        print(f"Successfully converted nested JSON to CSV: {csv_file_path}")
        return True

    except Exception as e:
        print(f"Error: {e}")
        return False

Complete Utility Class

Here's a comprehensive utility class that combines all the functionality:

import json
import csv
import os
from typing import List, Dict, Any, Union

class DataConverter:
    """A comprehensive utility class for converting between JSON and CSV formats."""

    @staticmethod
    def json_to_csv(json_file: str, csv_file: str, flatten_nested: bool = False) -> bool:
        """
        Convert JSON file to CSV format.

        Args:
            json_file (str): Path to input JSON file
            csv_file (str): Path to output CSV file
            flatten_nested (bool): Whether to flatten nested objects

        Returns:
            bool: Success status
        """
        try:
            with open(json_file, 'r', encoding='utf-8') as f:
                data = json.load(f)

            if not isinstance(data, list):
                data = [data]

            if flatten_nested:
                data = [DataConverter._flatten_dict(item) for item in data]

            if not data:
                raise ValueError("No data to convert")

            # Get fieldnames from first object
            fieldnames = list(data[0].keys())

            with open(csv_file, 'w', newline='', encoding='utf-8') as f:
                writer = csv.DictWriter(f, fieldnames=fieldnames)
                writer.writeheader()
                writer.writerows(data)

            print(f"โœ… Successfully converted {json_file} to {csv_file}")
            return True

        except Exception as e:
            print(f"โŒ Error converting JSON to CSV: {e}")
            return False

    @staticmethod
    def csv_to_json(csv_file: str, json_file: str, indent: int = 2) -> bool:
        """
        Convert CSV file to JSON format.

        Args:
            csv_file (str): Path to input CSV file
            json_file (str): Path to output JSON file
            indent (int): JSON indentation spaces

        Returns:
            bool: Success status
        """
        try:
            data = []

            with open(csv_file, 'r', encoding='utf-8') as f:
                reader = csv.DictReader(f)
                for row in reader:
                    # Convert numeric strings to numbers
                    converted_row = DataConverter._convert_types(row)
                    data.append(converted_row)

            if not data:
                raise ValueError("No data to convert")

            with open(json_file, 'w', encoding='utf-8') as f:
                json.dump(data, f, indent=indent, ensure_ascii=False)

            print(f"โœ… Successfully converted {csv_file} to {json_file}")
            return True

        except Exception as e:
            print(f"โŒ Error converting CSV to JSON: {e}")
            return False

    @staticmethod
    def _flatten_dict(nested_dict: Dict[str, Any], separator: str = '_') -> Dict[str, Any]:
        """Flatten a nested dictionary."""
        def _flatten(obj: Any, parent_key: str = '') -> Dict[str, Any]:
            items = []
            if isinstance(obj, dict):
                for k, v in obj.items():
                    new_key = f"{parent_key}{separator}{k}" if parent_key else k
                    items.extend(_flatten(v, new_key).items())
            elif isinstance(obj, list):
                for i, v in enumerate(obj):
                    new_key = f"{parent_key}{separator}{i}" if parent_key else str(i)
                    items.extend(_flatten(v, new_key).items())
            else:
                return {parent_key: obj}
            return dict(items)

        return _flatten(nested_dict)

    @staticmethod
    def _convert_types(row: Dict[str, str]) -> Dict[str, Union[str, int, float]]:
        """Convert string values to appropriate data types."""
        converted = {}
        for key, value in row.items():
            if value.isdigit():
                converted[key] = int(value)
            else:
                try:
                    converted[key] = float(value)
                except ValueError:
                    converted[key] = value
        return converted

# Usage examples
if __name__ == "__main__":
    converter = DataConverter()

    # Convert JSON to CSV
    converter.json_to_csv('customers.json', 'output.csv')

    # Convert CSV to JSON
    converter.csv_to_json('output.csv', 'output.json')

    # Convert with nested object flattening
    converter.json_to_csv('nested_data.json', 'flattened.csv', flatten_nested=True)

Troubleshooting Common Issues

Encoding Issues

Always specify UTF-8 encoding when working with files that contain special characters:

# Always use UTF-8 encoding
with open('file.json', 'r', encoding='utf-8') as f:
    data = json.load(f)

Memory Management for Large Files

For very large files, process data in chunks to avoid memory issues:

def process_large_json(json_file, csv_file, chunk_size=1000):
    """Process large JSON files in chunks."""
    with open(json_file, 'r') as f:
        data = json.load(f)

    with open(csv_file, 'w', newline='') as f:
        writer = None
        for i in range(0, len(data), chunk_size):
            chunk = data[i:i + chunk_size]
            if writer is None:
                writer = csv.DictWriter(f, fieldnames=chunk[0].keys())
                writer.writeheader()
            writer.writerows(chunk)

โš ๏ธ Important Note: This conversion method only works with JSON arrays containing objects with consistent structures. Heavily nested or irregular JSON structures require additional preprocessing to flatten the data properly.

Best Practices and Performance Tips

  • Validate the data structure first: Confirm your JSON is a list of objects before processing, and fail loudly if it is not โ€” a single scalar or a dict-of-dicts will produce garbage columns.
  • Handle missing keys: Use row.get(key, '') instead of row[key] when objects have inconsistent fields, or build fieldnames from the union of all keys so DictWriter never throws.
  • Open CSV files with newline='': This prevents the extra blank rows Windows inserts between records.
  • Always set encoding='utf-8': The Windows default (cp1252) silently corrupts accented characters and emoji.
  • Do not blindly cast every string to a number: Zip codes, phone numbers, and IDs with leading zeros will be destroyed. Cast only the columns you know are numeric.

The pandas Shortcut

If you already have pandas installed and your data is flat, the entire round trip collapses to a handful of lines. Reach for this when you also need to filter, pivot, or type-coerce โ€” but remember it loads the whole file into memory:

# Install pandas: pip install pandas
import pandas as pd

# JSON to CSV with pandas
df = pd.read_json('customers.json')
df.to_csv('customers.csv', index=False)

# CSV to JSON with pandas
df = pd.read_csv('customers.csv')
df.to_json('customers.json', orient='records', indent=2)

# Nested JSON? Flatten it on the way in:
# df = pd.json_normalize(json.load(open('nested.json')))

Conclusion and Next Steps

Converting between JSON and CSV formats is a fundamental skill for data processing and integration tasks. The techniques covered in this tutorial provide you with robust, production-ready solutions that handle common edge cases and errors gracefully.

Remember that JSON to CSV conversion works best with flat, consistent data structures. For complex nested data, you'll need to implement flattening logic or preprocess your data. CSV to JSON conversion is generally more straightforward but requires attention to data type conversion for optimal results.

Continue Learning

To further enhance your Python data processing skills, explore these related topics:

Frequently Asked Questions

How do I convert JSON to CSV in Python without pandas?

Use the standard library only. Read the JSON with json.load(), take the keys of the first object as your header row, then write rows with csv.DictWriter. A minimal version is: json.load(f) to get a list of dicts, csv.DictWriter(out, fieldnames=data[0].keys()), writer.writeheader(), then writer.writerows(data). No pip install is needed because both json and csv ship with Python 3.

Should I use the csv module or pandas to convert JSON to CSV?

Use the csv module for streaming, servers, and cases where you cannot add dependencies โ€” it uses almost no extra memory and handles quoting correctly. Use pandas when you already have it installed, need only two or three lines, or want to reshape, filter, or type-coerce the data on the way through. Pandas loads the whole dataset into memory, so it is the wrong tool for multi-gigabyte files.

Why does csv.DictWriter raise a ValueError about fields not in fieldnames?

DictWriter raises ValueError when a row contains a key that is not listed in fieldnames. This happens when your JSON objects have inconsistent keys โ€” the first object defines the header, but a later object has an extra field. Fix it by collecting the union of all keys across every object (a set comprehension) and passing extrasaction='ignore' or the full key set to DictWriter.

How do I flatten nested JSON so it fits in a CSV?

CSV is strictly two-dimensional, so nested objects and arrays must be flattened into dot- or underscore-joined column names before writing. Recursively walk the object, and for each nested key build a compound key like address_city or items_0_price. The flatten_json function in this guide does exactly this. Arrays become indexed columns, which is lossy โ€” consider keeping deeply nested data as JSON strings in a single column instead.

Why did my numbers turn into strings when converting CSV to JSON?

CSV has no types โ€” every field is read as a string. To restore numbers you must explicitly cast them. Check value.isdigit() for integers and wrap float(value) in a try/except for decimals, falling back to the original string on failure. Be careful: isdigit() returns False for negative numbers and decimals, and blindly casting can corrupt zip codes or IDs with leading zeros.

How do I handle very large JSON files without running out of memory?

json.load() reads the entire file into RAM, which fails on files larger than available memory. For large but line-delimited data (JSON Lines / NDJSON), read and write one record at a time so memory stays flat. For a single giant JSON array, use a streaming parser such as ijson to yield objects incrementally instead of loading the whole structure at once.

What encoding should I use when reading and writing these files?

Always pass encoding='utf-8' explicitly to open(). On Windows the default encoding is often cp1252, which corrupts accented characters and emoji. When writing JSON, also set ensure_ascii=False in json.dump() so non-ASCII characters are written as readable UTF-8 rather than \uXXXX escape sequences.

Why do I get blank rows between records in my output CSV?

Blank rows appear when the file is opened without newline=''. On Windows the csv module writes its own line terminators, and the default newline handling adds a second one. The fix is to always open CSV files for writing with open(path, 'w', newline='', encoding='utf-8').

Can I convert JSON to CSV directly in the browser without installing Python?

Yes. The interactive CSV / JSON converter embedded in this article runs entirely in your browser โ€” nothing is uploaded to a server. Paste JSON or CSV, choose the direction, and copy the result. It is the fastest option for one-off conversions or for checking that your Python output matches what you expect.