How to use
- Paste a JSON array of objects, drop a
.jsonor.jsonlfile on the box, or press Load sample. - Pick your database under Dialect and type the Table name.
- Choose how Nested objects are stored: kept as JSON text, or flattened into columns.
- Set Rows per INSERT, and untick Add CREATE TABLE if the table already exists.
- Copy to clipboard or Download .sql, or open the result in the SQL Formatter with Format this SQL.
How JSON values become SQL columns
Each object becomes a row and each key a column. The columns are every key that appears in any object, in the order they first appear, so objects with missing keys or keys in a different order still line up: a missing key is NULL. Because JSON already says what each value is, the column types follow it: numbers become INTEGER, BIGINT or a DECIMAL sized to the data (a number written with an exponent gets a floating-point type), true and false become a boolean, and strings stay text unless every one of them is a real date or timestamp.
Numbers are copied exactly as they appear in the JSON rather than through JavaScript's number type, so long IDs keep every digit. Nested objects and arrays are written as compact JSON into a JSON column (JSON in MySQL, JSONB in PostgreSQL, NVARCHAR(MAX) in SQL Server, TEXT in SQLite), or, with Flatten into columns, each nested key gets a column of its own named parent_child.
Strings are escaped the way the chosen database reads them, with the same rules as the CSV to SQL Converter: a doubled single quote everywhere, doubled backslashes for MySQL (which matters here, because JSON text inside a JSON column is full of backslashes) and N'…' for SQL Server.
Example
The array that Load sample inserts, with a null, an apostrophe, a nested object and an array:
[
{
"id": 1,
"name": "Ada Lovelace",
"email": "ada@example.com",
"active": true,
"signup": "2026-01-15",
"address": { "city": "London", "zip": "01234" },
"tags": ["admin", "beta"]
},
{
"id": 2,
"name": "Seán O'Brien",
"email": null,
"active": false,
"signup": "2026-02-03",
"address": { "city": "Dublin", "zip": null },
"tags": []
}
]becomes, with the default options (Standard SQL, nested objects kept as JSON text):
CREATE TABLE my_table (
id INTEGER,
name VARCHAR(12),
email VARCHAR(15),
active BOOLEAN,
signup DATE,
address VARCHAR(31),
tags VARCHAR(16)
);
INSERT INTO my_table (id, name, email, active, signup, address, tags) VALUES
(1, 'Ada Lovelace', 'ada@example.com', TRUE, '2026-01-15', '{"city":"London","zip":"01234"}', '["admin","beta"]'),
(2, 'Seán O''Brien', NULL, FALSE, '2026-02-03', '{"city":"Dublin","zip":null}', '[]');With PostgreSQL the two nested columns are address JSONB, tags JSONB. With Flatten into columns as well, the table starts like this, and tags stays JSON because it is an array:
CREATE TABLE my_table (
id INTEGER,
name TEXT,
email TEXT,
active BOOLEAN,
signup DATE,
address_city TEXT,
address_zip TEXT,
tags JSONB
);Options explained
- Dialect: Standard SQL, MySQL / MariaDB, PostgreSQL, SQL Server (T-SQL) or SQLite. It sets the quoting of names and strings, the boolean literals (TRUE/FALSE, or 1/0 in SQL Server and SQLite) and the type names, including which JSON column type is used.
- Table name: used in every statement and as the download's file name;
schema.tableworks. - Rows per INSERT: 1 / 100 / 500 / 1,000 / All rows in one INSERT. SQL Server is capped at 1,000 rows per statement, so larger batches are split for it.
- Add CREATE TABLE: untick it when the table already exists.
- Detect numbers, booleans and dates: untick it to make every column text and quote every value (nulls stay NULL).
- Nested objects: Keep as JSON text / Flatten into columns. Flattening goes as deep as the objects go; arrays are always kept as JSON.
- Column names in snake_case rewrites keys such as
createdAtorFirst Nameinto names that never need quotes.
Edge cases and common errors
- Invalid JSON is reported with its position, the same way the JSON Formatter does it: a trailing comma gives "Unexpected token ']' (line 1, column 12)".
- An array that mixes objects with other values cannot become rows: "Item 2 is a string, not an object. Each item becomes one row, so every item must be an object (or every item an array)."
- Objects with different keys share one column list, and a key an object lacks is NULL there:
[{"a": 1}, {"b": 2, "a": 3}]becomes
INSERT INTO my_table (a, b) VALUES
(1, NULL),
(3, 2);- An API response with the rows inside it is unwrapped: "The rows come from the "results" array inside the object."
- JSON Lines (one object per line, no surrounding array) is recognised: "Read as JSON Lines: one JSON value per line."
- Flattened names can collide with a key that already has that name, so the later one is renamed: "Two columns are called user_name; the later one is called user_name_2."
- Numbers with an exponent, such as
1.5e3, make the column floating point (DOUBLE PRECISIONin PostgreSQL) rather than an exact DECIMAL. - Large files: 10,000 objects (about 2 MB of JSON) convert in about 0.15 seconds on a laptop. For hundreds of thousands of rows a database loader is faster than an INSERT script.
Do the same thing in code
import json, sqlite3
import pandas as pd
rows = json.load(open("data.json", encoding="utf-8"))
df = pd.json_normalize(rows, sep="_") # nested keys become address_city
df = df.map(lambda v: json.dumps(v) if isinstance(v, list) else v)
df.to_sql("my_table", sqlite3.connect("data.db"), index=False)INSERT INTO my_table
SELECT * FROM jsonb_populate_recordset(NULL::my_table, '[{"id": 1, "name": "Ada"}]');pandas' json_normalize flattens nested objects much like Flatten into columns; lists have to be turned into JSON text first, which is the second line. PostgreSQL can also read the JSON itself: jsonb_populate_recordset maps each object onto an existing table's columns by name. If the data is going to a spreadsheet instead of a database, use the JSON to CSV Converter, and the SQL Formatter lays out the generated script before you run it.