SQL to Drizzle ORM Schema Converter
Convert PostgreSQL, MySQL, and SQLite CREATE TABLE DDL into Drizzle ORM TypeScript schemas (pgTable, mysqlTable, sqliteTable, relations, and $inferSelect).
Example Output (SQL to Drizzle Schema)
CREATE TYPE user_role AS ENUM ('ADMIN', 'MEMBER', 'VIEWER');
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) NOT NULL UNIQUE,
role user_role NOT NULL DEFAULT 'MEMBER',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
author_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(180) NOT NULL,
metadata JSONB,
published BOOLEAN NOT NULL DEFAULT false
);
CREATE INDEX idx_posts_author ON posts (author_id, published);import {
boolean,
index,
jsonb,
pgEnum,
pgTable,
serial,
timestamp,
uuid,
varchar,
} from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
export const userRoleEnum = pgEnum("user_role", ["ADMIN", "MEMBER", "VIEWER"]);
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
email: varchar("email", { length: 255 }).notNull().unique(),
role: userRoleEnum("role").default("MEMBER").notNull(),
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
});
export const posts = pgTable(
"posts",
{
id: serial("id").primaryKey(),
authorId: uuid("author_id").notNull().references(() => users.id, { onDelete: "cascade" }),
title: varchar("title", { length: 180 }).notNull(),
metadata: jsonb("metadata"),
published: boolean("published").default(false).notNull(),
},
(t) => ({
idxPostsAuthor: index("idx_posts_author").on(t.authorId, t.published),
})
);
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
}));
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;
export type Post = typeof posts.$inferSelect;
export type NewPost = typeof posts.$inferInsert;
Understanding the SQL to Drizzle Schema Transformation
Migrating raw SQL DDL statements (`CREATE TABLE`, `CREATE TYPE ... AS ENUM`, and `CREATE INDEX`) into Drizzle ORM requires mapping SQL types into dialect-specific column builders from `drizzle-orm/pg-core`, `drizzle-orm/mysql-core`, or `drizzle-orm/sqlite-core`. Unlike Prisma's custom DSL, Drizzle defines schemas directly in TypeScript where foreign keys require both database-level `.references(() => table.col)` constraints (for `drizzle-kit` migrations) and application-level `relations()` declarations (for `db.query.*` relational queries). This converter parses multi-table SQL schemas entirely in your browser and outputs idiomatic Drizzle TypeScript code.
Key Architectural Benefits
- •Generates both database-level `.references(() => parent.id, { onDelete })` constraints and Drizzle Query API `relations(table, ({ one, many }) => ...)` blocks.
- •Supports PostgreSQL (`pgTable`, `pgEnum`, `uuid().defaultRandom()`), MySQL (`mysqlTable`, `varchar`), and SQLite/Turso (`sqliteTable`, `integer({ mode: 'boolean' })`).
- •Translates composite `PRIMARY KEY (a, b)` constraints and `CREATE INDEX` statements into Drizzle's third-argument table callback `(t) => ({ pk: primaryKey(...), idx: index(...) })`.
- •Exports modern `typeof table.$inferSelect` and `typeof table.$inferInsert` TypeScript types instead of deprecated `InferModel` helpers.
Common Conversion Pitfalls & Fixes
Verified Edge Cases & Complex Scenarios
Real payloads often contain edge cases that break naive generators. Here is how our engine handles them:
A join table defines `PRIMARY KEY (post_id, tag_id)` across two foreign keys instead of a single `id` column.
CREATE TABLE post_tags (
post_id INTEGER NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (post_id, tag_id)
);export const postTags = pgTable(
"post_tags",
{
postId: integer("post_id").notNull().references(() => posts.id, { onDelete: "cascade" }),
tagId: integer("tag_id").notNull().references(() => tags.id, { onDelete: "cascade" }),
},
(t) => ({
pk: primaryKey({ columns: [t.postId, t.tagId] }),
})
);A PostgreSQL schema declares `CREATE TYPE status AS ENUM` alongside `TIMESTAMPTZ DEFAULT NOW()` and `UUID DEFAULT gen_random_uuid()`.
CREATE TYPE order_status AS ENUM ('PENDING', 'PAID');
CREATE TABLE orders (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
status order_status NOT NULL DEFAULT 'PENDING',
placed_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);export const orderStatusEnum = pgEnum("order_status", ["PENDING", "PAID"]);
export const orders = pgTable("orders", {
id: uuid("id").primaryKey().defaultRandom(),
status: orderStatusEnum("status").default("PENDING").notNull(),
placedAt: timestamp("placed_at", { withTimezone: true }).defaultNow().notNull(),
});Frequently Asked Questions
How do I infer TypeScript row types from a Drizzle table?
What is the difference between .references() and relations() in Drizzle ORM?
Is my SQL schema sent to any server during conversion?
Related Developer Converters
Browse AllSQL to Prisma Schema
Convert PostgreSQL and MySQL CREATE TABLE DDL statements into Prisma ORM models. Infers 1:1, 1:n, and n:m relations, enums, @default, @unique, and @@index.
JSON to Zod Schema
Convert raw JSON into strict, production-ready Zod schemas. Supports ISO datetime offsets, email, URLs, nullish options, and inferred TypeScript types in browser.
.env to Zod & T3 Env
Convert .env files into Zod v4, Zod v3, or @t3-oss/env-nextjs schemas in your browser. Infers types without exposing secret values and generates .env.example.