Quick answer
To convert SQL to Drizzle, turn each CREATE TABLE into a pgTable, mysqlTable or sqliteTable call and each column type into its Drizzle builder, such as varchar({ length: 255 }) or timestamp({ withTimezone: true }). Playxoft's free SQL to Drizzle Converter does this in your browser: paste PostgreSQL, MySQL or SQLite DDL and it writes schema.ts with keys, defaults, indexes, enums and relations(). Check its notes, then run drizzle-kit generate.
- PostgreSQL, MySQL and SQLite
- Indexes and composite keys
- pgEnum and mysqlEnum
- relations() from foreign keys
- camelCase keys, SQL names kept
- pg_dump and mysqldump input
- Line-numbered notes
How to use the SQL to Drizzle Converter
- 1Choose your Source database: PostgreSQL, MySQL or SQLite.
- 2Paste your CREATE TABLE statements, drop a .sql dump onto the editor, or click Load example.
- 3Set Dates, Bigint and camelCase keys to match how you want values to look in TypeScript.
- 4Read the Notes panel for anything skipped or approximated, and click a line number to jump to it in your SQL.
- 5Copy the code or download schema.ts, add it to your project and run
npx drizzle-kit generateto produce the SQL and compare it with your original DDL.
What is Drizzle ORM?
Drizzle ORM is a TypeScript ORM where the schema is plain TypeScript: every table is a pgTable, mysqlTable or sqliteTable call, and the types of your rows are inferred from it, with no code generation step. Queries look like SQL (db.select().from(users).where(eq(users.id, 1))), and a second, relational API (db.query.users.findMany({ with: { posts: true } })) loads nested data.
Its companion CLI, drizzle-kit, turns changes to that schema into SQL migrations (generate) or applies them to a database directly (push). That is why an accurate schema.ts matters: if it does not describe the tables you already have, the next push tries to "fix" the difference. This converter keeps SQL names, constraint names and defaults intact so the schema matches your database instead of only coming close.
How are SQL types mapped to Drizzle column builders?
Each dialect has its own Drizzle package, so the same SQL type can map to different builders:
| SQL type | PostgreSQL (pg-core) | MySQL (mysql-core) | SQLite (sqlite-core) |
|---|---|---|---|
integer / int | integer() | int() | integer() |
bigint | bigint({ mode: "number" }) | bigint({ mode: "number" }) | integer() |
serial / AUTO_INCREMENT | serial() | int().autoincrement() | integer().primaryKey({ autoIncrement: true }) |
varchar(255) | varchar({ length: 255 }) | varchar({ length: 255 }) | text({ length: 255 }) |
boolean | boolean() | boolean() (tinyint(1)) | integer({ mode: "boolean" }) |
timestamptz | timestamp({ withTimezone: true }) | timestamp() | text() |
numeric(10,2) | numeric({ precision: 10, scale: 2 }) | decimal({ precision: 10, scale: 2 }) | numeric() |
json / jsonb | json() / jsonb() | json() | text({ mode: "json" }) |
uuid | uuid() | char({ length: 36 }) | text() |
| enum | pgEnum("name", […]) | mysqlEnum([…]) | text({ enum: […] }) |
text[] | text().array() | not supported | not supported |
A few details trip people up. numeric and decimal columns return strings by default, so money never passes through a floating-point number. bigint needs a mode: "number" is exact only up to 2^53. SQLite has no date type, so date columns become text() unless you store Unix time. Types Drizzle does not ship, such as citext or tsvector, become a small customType declared at the top of the file.
How does the converter create foreign keys and relations?
Foreign keys become real constraints first. An unnamed single-column REFERENCES turns into .references(() => users.id, { onDelete: "cascade" }) on the column. Composite or named foreign keys go into the table's extra-config array as foreignKey({ name, columns, foreignColumns }), so the constraint name in your database is preserved.
Then, with Relations on, each foreign key also produces a pair of relations() entries for the relational query API:
export const postsRelations = relations(posts, ({ one, many }) => ({
author: one(users, {
fields: [posts.authorId],
references: [users.id],
}),
comments: many(comments),
}));Names come from the column (author_id becomes author) and the child table (posts). When two tables are linked more than once, or a table references itself, the converter adds a relationName so Drizzle can tell the relations apart, and self-references are typed with AnyPgColumn to avoid TypeScript's circular-type error.
Should I use drizzle-kit pull instead?
drizzle-kit pull introspects a live database and writes the schema for you. It is the right choice when you can connect to the database and want an exact snapshot. This converter is faster when you cannot, or do not want to:
| Situation | drizzle-kit pull | This converter |
|---|---|---|
| You only have a .sql file, migration or dump | Needs a running database first | Paste it and go |
| Production sits behind a VPN or firewall | Needs credentials and network access | Nothing to connect |
| Converting one table or a snippet | Pulls the whole database | Converts exactly what you paste |
| Trying naming and type options | Rerun with new config each time | Toggle and see the result live |
| Views and row-level security policies | Introspected where supported | Skipped, with a note |
A common workflow is to convert here, commit the schema, then run drizzle-kit generate (no database connection needed) and diff the SQL it writes against your original DDL, or drizzle-kit push to a scratch database.
What does the converter not handle?
It reads tables, columns, keys, indexes, enums, domains and comments. Anything else is reported in the Notes panel with a line number rather than silently dropped:
- Views, functions, triggers and policies are skipped: they are not part of a Drizzle table schema.
- CHECK constraints are kept as comments above the table, so you can turn them into
check()calls if you want drizzle-kit to manage them. - MySQL FULLTEXT indexes and prefix lengths (
name(191)) have no Drizzle builder; create them in a custom migration. - Exclusion constraints and
INHERITSare PostgreSQL features Drizzle cannot express.
If your SQL is messy, run it through the SQL formatter first; the line numbers in the notes are easier to follow in tidy SQL.
Frequently asked questions
Last updated by the Playxoft engineering team.