To convert a pandas DataFrame to JSON, call df.to_json(). The orient argument decides the shape: orient="records" gives the most common format, a JSON array with one object per row. Add indent=2 for readable output or a file path to save it. This guide compares every orient on the same DataFrame, then covers pretty printing, files and JSON Lines, dates, non-ASCII text and missing values, and reading the JSON back into a DataFrame.
All examples were run with Python 3.12.5 and pandas 3.0.6 in the Windows Command Prompt. Reference: DataFrame.to_json in the pandas documentation.
DataFrame to a JSON array
import pandas as pd
df = pd.DataFrame({
"id": [101, 102, 103],
"name": ["Anna", "Ben", "Chen"],
"score": [91.5, 78.0, 85.25],
})
print(df.to_json(orient="records")) # a JSON array: one object per row
Output:
[{"id":101,"name":"Anna","score":91.5},{"id":102,"name":"Ben","score":78.0},{"id":103,"name":"Chen","score":85.25}]
to_json orient options
The same three-row DataFrame, converted with each orient:
import pandas as pd
df = pd.DataFrame({
"id": [101, 102, 103],
"name": ["Anna", "Ben", "Chen"],
"score": [91.5, 78.0, 85.25],
})
for orient in ["records", "columns", "index", "split", "values"]:
print(f"{orient:<8}", df.to_json(orient=orient))
Output:
records [{"id":101,"name":"Anna","score":91.5},{"id":102,"name":"Ben","score":78.0},{"id":103,"name":"Chen","score":85.25}]
columns {"id":{"0":101,"1":102,"2":103},"name":{"0":"Anna","1":"Ben","2":"Chen"},"score":{"0":91.5,"1":78.0,"2":85.25}}
index {"0":{"id":101,"name":"Anna","score":91.5},"1":{"id":102,"name":"Ben","score":78.0},"2":{"id":103,"name":"Chen","score":85.25}}
split {"columns":["id","name","score"],"index":[0,1,2],"data":[[101,"Anna",91.5],[102,"Ben",78.0],[103,"Chen",85.25]]}
values [[101,"Anna",91.5],[102,"Ben",78.0],[103,"Chen",85.25]]
| orient | Shape | Good for |
|---|---|---|
records | [{"id":101,...}, ...] | APIs, JavaScript, most tools |
columns (default) | {"id":{"0":101,...}, ...} | Column-oriented storage |
index | {"0":{"id":101,...}, ...} | Looking rows up by index |
split | {"columns":[...],"index":[...],"data":[...]} | Compact, keeps column order |
values | [[101,"Anna",91.5], ...] | Just the data |
table | JSON Table Schema + data | Keeping dtypes and schema |
Pretty-print with indent
import pandas as pd
df = pd.DataFrame({
"id": [101, 102, 103],
"name": ["Anna", "Ben", "Chen"],
"score": [91.5, 78.0, 85.25],
})
print(df.to_json(orient="records", indent=2)) # readable, multi-line JSON
Output:
[
{
"id":101,
"name":"Anna",
"score":91.5
},
{
"id":102,
"name":"Ben",
"score":78.0
},
{
"id":103,
"name":"Chen",
"score":85.25
}
]
indent=2 makes the JSON readable.pandas writes "id":101 without a space after the colon. If you need the exact formatting of json.dumps(), use the to_dict() route shown below.
Save a DataFrame as a JSON file (and JSON Lines)
Pass a path as the first argument. lines=True (with orient="records") writes JSON Lines, one object per line, which is easy to append to and to stream:
import os
import pandas as pd
df = pd.DataFrame({
"id": [101, 102, 103],
"name": ["Anna", "Ben", "Chen"],
"score": [91.5, 78.0, 85.25],
})
df.to_json("scores.json", orient="records", indent=2) # a normal JSON file
df.to_json("scores.jsonl", orient="records", lines=True) # JSON Lines: one object per line
print(open("scores.jsonl").read())
print({name: os.path.getsize(name) for name in ["scores.json", "scores.jsonl"]}, "bytes")
Output:
{"id":101,"name":"Anna","score":91.5}
{"id":102,"name":"Ben","score":78.0}
{"id":103,"name":"Chen","score":85.25}
{'scores.json': 179, 'scores.jsonl': 114} bytes
Dates, non-ASCII text and missing values
By default, datetimes become milliseconds since 1970 and non-ASCII characters are escaped. In pandas 3 this default also prints a Pandas4Warning saying the epoch format is deprecated, so pass date_format="iso" (and force_ascii=False for readable text). NaN is always written as null:
import numpy as np
import pandas as pd
df = pd.DataFrame({
"city": ["São Paulo", "Zürich"],
"joined": pd.to_datetime(["2025-07-04 09:30", "2025-08-15 14:00"]),
"rating": [4.5, np.nan],
})
print(df.to_json(orient="records")) # epoch milliseconds, \u escapes
print(df.to_json(orient="records", date_format="iso", force_ascii=False)) # ISO dates, real characters
Output:
C:\pyguides\dataframe_to_json_dates.py:10: Pandas4Warning: The default 'epoch' date format is deprecated and will be removed in a future version, please use 'iso' date format instead.
print(df.to_json(orient="records")) # epoch milliseconds, \u escapes
[{"city":"S\u00e3o Paulo","joined":1751621400000,"rating":4.5},{"city":"Z\u00fcrich","joined":1755266400000,"rating":null}]
[{"city":"São Paulo","joined":"2025-07-04T09:30:00.000","rating":4.5},{"city":"Zürich","joined":"2025-08-15T14:00:00.000","rating":null}]
date_format="iso", force_ascii=False.Build custom JSON with to_dict and json.dumps
When the JSON must match a specific structure (for example an API response with extra fields), convert to Python objects first:
import json
import pandas as pd
df = pd.DataFrame({
"id": [101, 102, 103],
"name": ["Anna", "Ben", "Chen"],
"score": [91.5, 78.0, 85.25],
})
records = df.to_dict(orient="records") # a list of Python dicts
print(records)
payload = json.dumps({"count": len(records), "results": records}, indent=2) # wrap it in your own JSON
print(payload)
Output:
[{'id': 101, 'name': 'Anna', 'score': 91.5}, {'id': 102, 'name': 'Ben', 'score': 78.0}, {'id': 103, 'name': 'Chen', 'score': 85.25}]
{
"count": 3,
"results": [
{
"id": 101,
"name": "Anna",
"score": 91.5
},
{
"id": 102,
"name": "Ben",
"score": 78.0
},
{
"id": 103,
"name": "Chen",
"score": 85.25
}
]
}
Read the JSON back into a DataFrame
from io import StringIO
import pandas as pd
df = pd.DataFrame({
"id": [101, 102, 103],
"name": ["Anna", "Ben", "Chen"],
"score": [91.5, 78.0, 85.25],
})
text = df.to_json(orient="records")
df2 = pd.read_json(StringIO(text), orient="records") # wrap literal JSON in StringIO
print(df2)
print("same data:", df.equals(df2))
Output:
id name score
0 101 Anna 91.50
1 102 Ben 78.00
2 103 Chen 85.25
same data: True
Recent pandas versions warn when you pass a JSON string directly to read_json(); wrap it in StringIO or pass a file path.
Related pandas and conversion tutorials:
- Convert a dictionary to JSON in Python
- Convert a dictionary to a string
- Read a CSV file with pandas
- Read a CSV file into a dictionary with pandas
Frequently asked questions
How do I convert a pandas DataFrame to JSON?
Use df.to_json(orient="records") for a JSON array of row objects, or another orient for a different shape.
How do I convert a DataFrame to a JSON array?
df.to_json(orient="records") returns [{...}, {...}], one object per row.
How do I pretty-print DataFrame JSON?
Pass indent: df.to_json(orient="records", indent=2).
How do I save a DataFrame as a JSON file?
df.to_json("file.json", orient="records", indent=2); add lines=True for JSON Lines.
Why are my dates numbers in the JSON?
to_json writes datetimes as epoch milliseconds by default. Use date_format="iso".
How do I keep accented characters in the JSON?
Use force_ascii=False; otherwise characters like é are written as \u00e9.
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn