Prisma Schema to SQL

Paste a schema.prisma and get runnable CREATE TABLE DDL — columns with Prisma's own type mapping, PRIMARY KEY and index statements, enums, and foreign keys with ON DELETE/ON UPDATE actions. PostgreSQL, MySQL, SQLite and SQL Server. Nothing is executed; it all runs in your browser.

Try:
SQL DDL

About this tool

This tool reads a Prisma schema.prisma and writes the CREATE TABLE DDL that would build the same database. Paste your models, pick a dialect, and you get a script you can hand to psql, mysql, sqlite3 or sqlcmd — or paste into a migration file, a docker-entrypoint seed script, or a code review to show exactly what a schema change does at the SQL level.

Nothing is executed and no database is contacted: the schema is parsed and mapped inside your browser, and the result is text.

What each part of the schema becomes

Type mapping

PrismaPostgreSQLMySQLSQLiteSQL Server
StringTEXTVARCHAR(191)TEXTNVARCHAR(1000)
BooleanBOOLEANTINYINT(1)BOOLEANBIT
IntINTEGERINTINTEGERINT
BigIntBIGINTBIGINTBIGINTBIGINT
FloatDOUBLE PRECISIONDOUBLEREALFLOAT(53)
DecimalDECIMAL(65,30)DECIMAL(65,30)DECIMALDECIMAL(32,16)
DateTimeTIMESTAMP(3)DATETIME(3)DATETIMEDATETIME2
JsonJSONBJSONJSONBnot supported
BytesBYTEALONGBLOBBLOBVARBINARY(MAX)

A @db.* attribute always wins over the row above.

The toggles

SQL dialect defaults to Auto, which reads the datasource block's provider and falls back to PostgreSQL when the schema has no datasource — handy when you paste only the models. Emit foreign-key constraints and Emit index statements let you keep just the bare tables, which is what you usually want when seeding a scratch database and loading data before the constraints go on. Add IF NOT EXISTS guards makes the script re-runnable, and Prepend DROP TABLE IF EXISTS makes it rebuild from zero — that one is destructive, so keep it for throwaway databases. Quote identifiers is on by default because Prisma's camelCase table and column names need quoting to survive; turn it off for a lowercase, folded-identifier script.

Worked example

Schema:

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
}

PostgreSQL output:

CREATE TABLE "User" (
    "id" SERIAL NOT NULL,
    "email" TEXT NOT NULL,
    "name" TEXT,
    CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

CREATE UNIQUE INDEX "User_email_key" ON "User"("email");

Limits & edge cases

FAQ

Is this the same SQL that Prisma Migrate would generate?

It is very close, and it follows the same type map, the same constraint and index naming (Table_column_key, Table_column_idx, Table_pkey) and the same referential-action defaults, so the two line up on ordinary schemas. It is not a byte-for-byte reimplementation of the migration engine, though: statement ordering, some provider-specific edge cases and any feature-preview behaviour can differ. Treat the result as a very good starting script and review it before running it against anything you care about.

Why does my @default(uuid()) column have no DEFAULT?

Because uuid(), cuid(), ulid(), nanoid() and auto() are generated by Prisma Client in your application, not by the database — the column genuinely has no server-side default in a Prisma-managed schema either. If you want the database to generate the value, express that explicitly with @default(dbgenerated("gen_random_uuid()")), and the expression is passed straight through into the DDL.

What happens to my enums on SQLite and SQL Server?

Neither dialect has a native enum type, so the column is emitted as TEXT (SQLite) or NVARCHAR(1000) (SQL Server) with a CHECK (col IN ('A', 'B')) constraint that enforces the same set of values. On PostgreSQL you get a real CREATE TYPE … AS ENUM and the column references it; on MySQL you get an inline ENUM('A', 'B') column. @map on an enum value is respected everywhere, so the database sees the mapped string, not the Prisma identifier.

Do I get foreign keys for both sides of a relation?

No — and that is correct. A Prisma relation is written on both models, but only one side carries fields: and references:, and that is the side that owns the column and therefore the foreign key. The back-relation field (posts Post[] on User, say) produces neither a column nor a constraint. All the foreign keys are emitted as ALTER TABLE statements after every CREATE TABLE, so you can run the script top to bottom regardless of the order your models are in.

Can I run the script twice, or rebuild a scratch database from zero?

Yes. Add IF NOT EXISTS guards makes every CREATE TABLE (and, on PostgreSQL and SQLite, every index) skip quietly if the object is already there; on SQL Server it becomes an IF OBJECT_ID(…) IS NULL guard, since that dialect has no IF NOT EXISTS on CREATE TABLE. Prepend DROP TABLE IF EXISTS goes further and drops everything first, in reverse creation order, plus the PostgreSQL enum types. That second one destroys data, so point it only at a throwaway database.

What if I only paste the models, with no datasource block?

That works. The SQL dialect control defaults to Auto, which looks for a datasource block and uses its provider; with no datasource to read, it falls back to PostgreSQL. Pick a dialect explicitly from the dropdown whenever you want a specific target, and the datasource — if there is one — is ignored.

Developer & Automation Access

Run it from the terminal

Same engine as this page, headless — via the gizza CLI:

gizza tool prisma-schema-to-sql "model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
}"

New to the CLI? Get gizza →

Open it by URL

Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:

https://gizza.ai/tools/prisma-schema-to-sql/?input=model%20User%20%7B%0A%20%20id%20%20%20%20Int%20%20%20%20%20%40id%20%40default%28autoincrement%28%29%29%0A%20%20email%20String%20%20%40unique%0A%20%20name%20%20String%3F%0A%7D&dialect=auto&foreign_keys=true&indexes=true&if_not_exists=true&drop_if_exists=true&quote_identifiers=true

Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.