What is JSON to Prisma Schema Generator?
Prisma is a type-safe ORM for Node.js and TypeScript that uses a single declarative file — schema.prisma — as the source of truth for both your database tables and the generated TypeScript client. This tool reads a sample JSON document or an array of records and produces a Prisma model block, inferring each field's scalar type, marking nullable fields with the ? modifier, and adding the annotations a real schema needs (@id, @default, @unique, @updatedAt). There are two distinct scenarios where this is useful, and they lead to different schemas. The first is greenfield modeling: you have an API response or a sample payload and you want to bootstrap a brand-new table to store it. Here the generator gives you a starting model that you tweak. The second is the SQL-to-Prisma path: you already have a live database and you run prisma db pull (introspection) to reverse-engineer it. In that case the generated schema reflects existing columns, constraints, and relations exactly — and you would not hand-edit types because the next introspection would overwrite them. The trickiest part of any JSON-derived schema is what to do with nested objects and arrays. A relational database has no native concept of an embedded object, so Prisma offers the Json scalar type for PostgreSQL, MySQL, and SQLite. The generator maps any nested object or array to Json by default. That is correct for unstructured blobs (settings, metadata, raw webhook bodies) but wrong for data that should be a related table — so you often replace a Json field with a proper relation after generating.
How to Use
- Decide your scenario first: bootstrapping a NEW table from a JSON sample (use this tool, then edit), or reverse-engineering an EXISTING database (prefer prisma db pull instead, which preserves real constraints)
- Set the model name in PascalCase (Prisma convention) — e.g. "User", "OrderItem" — and pick the datasource provider, because Json support and native types differ between PostgreSQL, MySQL, and SQLite
- Paste an ARRAY of several records rather than one object: a single sample cannot tell the generator whether a field is sometimes null, so multiple rows produce more accurate ? modifiers
- After generating, replace any Json field that represents a real one-to-many or many-to-one relationship with a proper model and a relation (@relation), and add @@index on columns you will filter by
- Run npx prisma format to normalize spacing and alignment, then npx prisma migrate dev --name init to create the migration and apply it
Why Use This Tool?
Tips & Best Practices
- Json fields are stored as opaque blobs — you CANNOT add @unique or @@index on their inner keys in MySQL/SQLite, and querying them requires the path/filter helpers. If you need to query a value, promote it to its own column
- @updatedAt is updated by the Prisma Client, NOT by the database. A raw SQL UPDATE outside Prisma will not bump the timestamp — this surprises people debugging stale updatedAt values
- @default(cuid()) and @default(uuid()) are generated application-side by Prisma; @default(autoincrement()) is generated by the database. Choose cuid()/uuid() if you need the id before the INSERT (e.g. to build relations in a single transaction)
- For an Int that exceeds 2^31 (timestamps in ms, large counters) use BigInt — the generator may infer Int from a small sample, so widen it manually or you will hit overflow in PostgreSQL
- Prisma requires every model to have a unique identifier (@id or @@unique). If your JSON has no id-like field, add one before migrating or the schema will not validate
Frequently Asked Questions
What is the complete JSON type to Prisma type mapping?
JSON string → String (or DateTime when the value is an ISO 8601 date). JSON integer → Int (widen to BigInt for values beyond 2^31). JSON float → Float (use Decimal @db.Decimal(p,s) for money). JSON boolean → Boolean. JSON null → the field becomes optional with the ? modifier, e.g. String?. JSON nested object → Json. JSON array of primitives → Json, or String[] / Int[] on PostgreSQL which supports native scalar lists. JSON array of objects → Json by default, but this is the usual signal to model a separate related table instead.
When should I use the Json type versus a separate model and relation?
Use Json for genuinely unstructured or schema-less data you never query by inner field: user preferences, third-party API payloads, feature flags, audit snapshots. Use a separate model with @relation when the nested data has a stable shape, needs to be queried or filtered, needs its own constraints, or represents a real entity. A common mistake is leaving an array of objects as Json — if those objects are, say, order line items, they belong in an OrderItem model with a foreign key back to Order.
What is the difference between @default and @updatedAt?
@default sets a value when a row is CREATED if you do not supply one — e.g. @default(now()) for createdAt, @default(autoincrement()) for an id, @default(false) for a boolean flag. @updatedAt is special: Prisma rewrites that column to the current time on every UPDATE the Prisma Client performs. They are complementary — createdAt typically uses @default(now()) and is never touched again, while updatedAt uses @updatedAt and changes on each modification.
Should I generate the schema or use prisma db pull?
If the database does not exist yet and you are designing it from a JSON sample, generate here and then run prisma migrate dev. If the database already exists, use prisma db pull (introspection): it reads the real columns, types, indexes, and foreign keys and writes an accurate schema, including relations this tool cannot infer from a single JSON document. Generating from JSON is for greenfield modeling; db pull is for adopting an existing schema.
Why is my nullable field not optional in the generated schema?
The generator can only mark a field optional (String?) if it actually sees a null value in your sample. If you paste one record where every field is populated, every field looks required. Paste an array that includes records with missing or null values, or add the ? manually. Getting this right matters because a non-optional field forces a value on every create() call.
Does this tool send my data to a server?
No. All schema generation runs entirely in your browser. Your JSON never leaves your device.
Real-world Examples
User table from a signup API payload
A signup endpoint returns the created user. The id should be an autoincrement primary key, email must be unique, the optional bio came back null for this user (so it becomes String?), and we add audit timestamps. The settings object is genuinely unstructured, so Json is the right choice here.
{
"id": 1,
"email": "ada@example.com",
"name": "Ada Lovelace",
"bio": null,
"isVerified": true,
"settings": { "theme": "dark", "emailDigest": "weekly" },
"createdAt": "2024-03-01T12:00:00Z"
}model User {
id Int @id @default(autoincrement())
email String @unique
name String
bio String?
isVerified Boolean @default(false)
settings Json
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}Order with line items — why an array of objects should become a relation
The order JSON embeds an items array. The naive mapping turns items into a single Json column, but line items are a real entity you will query and aggregate. The better schema promotes them to an OrderItem model with a foreign key. This is the most common manual edit after generating.
{
"id": "ord_1001",
"total": 49.98,
"items": [
{ "sku": "TS-RED-M", "qty": 1, "price": 19.99 },
{ "sku": "MUG-01", "qty": 1, "price": 29.99 }
]
}model Order {
id String @id
total Decimal @db.Decimal(10, 2)
items OrderItem[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model OrderItem {
id Int @id @default(autoincrement())
sku String
qty Int
price Decimal @db.Decimal(10, 2)
order Order @relation(fields: [orderId], references: [id])
orderId String
@@index([orderId])
}