SQL to Drizzle Schema
Generate a Drizzle ORM schema from a SQL CREATE TABLE statement.
Related Tools
Generate a Prisma schema model from a SQL CREATE TABLE statement.
Generate a TypeORM entity class from a SQL CREATE TABLE statement.
Generate a SQLAlchemy declarative model from a SQL CREATE TABLE statement.
Convert CSV rows into SQL INSERT statements.
Generate TypeScript interfaces or type aliases from JSON.
Generate a Sequelize model from a SQL CREATE TABLE statement.
Documentation
What is SQL to Drizzle?
SQL to Drizzle turns CREATE TABLE statements into a Drizzle ORM schema file using drizzle-orm/pg-core — one pgTable() call per table, built from column builder functions chained with modifiers like .primaryKey() and .notNull().
How it works
Each column's SQL type picks a pg-core builder function — INTEGER/SERIAL → integer() (or serial() when auto-incrementing), VARCHAR(n) → varchar('col', { length: n }), TIMESTAMP → timestamp(), UUID → uuid(), and so on — then chains .primaryKey(), .notNull(), and .unique() based on the parsed constraints. Postgres's SERIAL/BIGSERIAL auto-increment is expressed purely through the column type itself (serial()/bigserial()), not a separate flag, matching how Postgres actually implements it as a sequence-backed default. Only literal defaults and CURRENT_TIMESTAMP/NOW() (translated to .default(sql`now()`), importing sql from drizzle-orm only when needed) are converted; anything else becomes a trailing comment. The import line at the top of the file is assembled dynamically from exactly the builder functions your schema actually used.
Features
- One
pgTable()export perCREATE TABLE, named in camelCase - Type-aware builder selection, including
varcharlength andnumericprecision/scale - Auto-generated import list scoped to only the builders actually used
- Literal and
now()defaults translated; everything else left as a comment - Copy or download the generated
.tsschema file
Example
Input:
CREATE TABLE users ( id SERIAL PRIMARY KEY, external_id UUID DEFAULT uuid_generate_v4(), name VARCHAR(255) NOT NULL, is_active BOOLEAN DEFAULT true ); CREATE TABLE posts ( id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id), title VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
Output:
import { sql } from 'drizzle-orm';
import { boolean, integer, pgTable, serial, timestamp, uuid, varchar } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
externalId: uuid('external_id'), // SQL default not translated: uuid_generate_v4()
name: varchar('name', { length: 255 }).notNull(),
isActive: boolean('is_active').default(true),
});
export const posts = pgTable('posts', {
id: serial('id').primaryKey(),
userId: integer('user_id').notNull(), // FK -> users.id
title: varchar('title', { length: 255 }).notNull(),
createdAt: timestamp('created_at').default(sql`now()`),
});Common errors
A DEFAULT the tool can't confidently translate, like uuid_generate_v4(), is never guessed at — it's left as a plain // SQL default not translated: uuid_generate_v4() comment next to the column so you can add .default(sql`gen_random_uuid()`) or the equivalent yourself. Foreign keys appear only as // FK -> table.column comments — Drizzle's .references(() => otherTable.column) needs a live reference to the other table's exported object, which the generator can't safely construct across separate schema files, so that wiring is left to you. If you're targeting MySQL or SQLite instead of Postgres, remember the output is pg-core-specific — some builder names and options differ between dialects.
Best practices
After pasting the output into your schema file, grep for not translated and FK -> to find every column needing manual follow-up, then run drizzle-kit generate to confirm the schema compiles and produces the migration you expect before applying it.
Frequently Asked Questions
Why pg-core specifically?▾
Postgres is the most common target for new Drizzle projects, so the generated import comes from drizzle-orm/pg-core. If you're on MySQL or SQLite, swap the import and a few column builder names (e.g. varchar stays similar, but some types differ) — the column options (notNull, unique, default) carry over conceptually.
Are foreign keys wired up with .references()?▾
Not automatically — a foreign key column gets a plain column definition plus a comment noting the target table/column. Drizzle's .references() needs a direct reference to the other table's exported column object, which requires both schema files to exist together; wiring that up is left for you to connect.
How does it decide between integer, bigint, and smallint?▾
Directly from the SQL type: INT/INTEGER/SERIAL become integer(), BIGINT/BIGSERIAL become bigint() with mode: 'number', and SMALLINT/SMALLSERIAL become smallint() — matching Postgres's own type hierarchy.
What about VARCHAR length or DECIMAL precision?▾
Both are preserved — VARCHAR(255) becomes varchar('col', { length: 255 }) and DECIMAL(10,2) becomes numeric('col', { precision: 10, scale: 2 }).