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.
