New blogMaking an AI Agent You Can Trust With Money

★ Prisma · from JSON

JSON to Prisma Converter

A first draft of your Prisma schema from real data. Scalars map to Prisma types, an id key becomes @id, awkward keys get @map, and nested objects start life as Json with a note on when to promote them to relations.

  • Runs in your browser
  • No signup

Strictness

Your JSON

Prisma

3 types · 16 fields
// Nested objects are stored as Json. Promote them to relations if you query them.

model Root {
  id          Int      @id
  email       String
  displayName String   @map("display-name")
  createdAt   DateTime
  plan        Json?
  tags        String[]
  team        Json                          // Team: make it a relation if you query it
  invoices    Json                          // list of Invoice: make it a relation if you query it
}

model Invoice {
  id     Int       @id @default(autoincrement()) // added: Prisma needs a unique id
  number String
  amount Float
  paid   Boolean
  paidAt DateTime?
  note   String?
}

model Team {
  id      String @id @default(uuid())
  name    String
  website String
}

Typing APIs by hand?

I set up end-to-end type safety (DB → API → UI) so this never happens again.

Fix my types
01

How the Prisma mapping works

Each JSON value is read, merged with every other sample of the same key, and then mapped to the closest Prisma type:

JSON to Prisma mapping
In your JSONPrisma
stringString
ISO timestamp / dateDateTime
integer / decimalInt / Float
true / falseBoolean
null or missingT?
array of scalarsString[] (scalar list)
nested object or array of objectsJson (relation suggested)
key "id"@id (uuid strings get @default(uuid()))
invalid or dashed keycamelCase field + @map("key")
02

Worked example

A user record with a nested team, a list of invoices (one missing a note, one with a null payment date) and an awkward display-name key:

{
  "id": 1042,
  "email": "ada@example.com",
  "display-name": "Ada",
  "createdAt": "2026-11-07T09:30:00Z",
  "plan": null,
  "tags": ["beta", "founder"],
  "team": {
    "id": "7f3c9a2e-1b4d-4c8e-9f2a-6d5e4c3b2a19",
    "name": "Analytical Engines",
    "website": "https://example.com"
  },
  "invoices": [
    { "number": "INV-001", "amount": 49.5, "paid": true, "paidAt": "2026-10-01T00:00:00Z" },
    { "number": "INV-002", "amount": 49, "paid": false, "paidAt": null, "note": "Card declined" }
  ]
}

Becomes this Prisma, generated by the same engine that runs the converter above (3 types, 16 fields):

// Nested objects are stored as Json. Promote them to relations if you query them.

model Root {
  id          Int      @id
  email       String
  displayName String   @map("display-name")
  createdAt   DateTime
  plan        Json?
  tags        String[]
  team        Json                          // Team: make it a relation if you query it
  invoices    Json                          // list of Invoice: make it a relation if you query it
}

model Invoice {
  id     Int       @id @default(autoincrement()) // added: Prisma needs a unique id
  number String
  amount Float
  paid   Boolean
  paidAt DateTime?
  note   String?
}

model Team {
  id      String @id @default(uuid())
  name    String
  website String
}
03

Prisma gotchas

Scalar lists are database-specific

String[] works on PostgreSQL and CockroachDB, not MySQL or SQLite. Use Json or a related table there.

Every model needs an id

Prisma requires a unique identifier. Models without an id key get id Int @id @default(autoincrement()), marked with a comment.

Json is a starting point

Json columns are easy to write and hard to query. Promote nested objects you filter or join on to real models with @relation.

04

Questions developers actually ask

Why aren't nested objects relations?
A relation needs foreign keys and a decision about ownership that a JSON sample can't tell you. The comments mark where a relation probably belongs.
Should Int ids be BigInt?
If ids can pass about 2.1 billion, yes. JSON doesn't reveal the range, so the tool uses Int; change it before your first migration.
How do I keep the original column names?
Fields whose name changed get @map("original-key"), so the database column keeps the JSON spelling while the client uses camelCase.
Is my JSON sent to a server?
No. Parsing and type generation run in your browser, so you can paste real API responses with tokens or customer data. Nothing leaves the tab.
How does it know a field is optional?
Paste an array of objects, or a response that contains one. Every element is read and merged: keys missing from some elements become optional, and keys that are sometimes null become nullable.
05

Other languages

06

More from the workbench

Fine print

Tools: on the house.
Engineer: by the hour.

A codebase that doesn't need this tool is the upgrade. I set up end-to-end type safety so your API, database and UI agree by construction.

I'm Himanshu, an AI and full-stack engineer. I build MVPs, AI agents and the growth plumbing around them for early-stage startups.