Drizzle ORM is a TypeScript ORM for SQL databases designed with maximum type safety in mind. It comes with a drizzle-kit CLI companion for automatic SQL migrations generation. Drizzle ORM is meant to be a library, not a framework. It stays as an opt-in solution all the time at any levels.
The ORM main philosophy is "If you know SQL, you know Drizzle ORM". We follow the SQL-like syntax whenever possible, are strongly typed ground up and fail at compile time, not in runtime.
Drizzle ORM is being battle-tested on production projects by multiple teams 🚀 Give it a try and let us know if you have any questions or feedback on Discord.
- Full type safety
- Smart automated migrations generation
- No ORM learning curve
- SQL-like syntax for table definitions and queries
- Best in class fully typed joins
- Fully typed partial and non-partial selects of any complexity
- Auto-inferring of TS types for DB models for selections and insertions separately
- Zod schema generation
- Zero dependencies
| Database | Status | |
|---|---|---|
| PostgreSQL | ✅ | Docs |
| MySQL | ✅ | Docs |
| SQLite | ✅ | Docs |
| Cloudflare D1 | ✅ | Docs |
| libSQL | ✅ | Docs |
| Turso | ✅ | Docs |
| DynamoDB | ⏳ | |
| MS SQL | ⏳ | |
| CockroachDB | ⏳ |
npm install drizzle-orm
npm install -D drizzle-kitNote: don't forget to install
pgand@types/pgpackages for this example to work.
import{drizzle}from'drizzle-orm/node-postgres';import{integer,pgTable,serial,text,timestamp,varchar}from'drizzle-orm/pg-core';import{InferModel,eq,sql}from'drizzle-orm';import{Pool}from'pg';exportconstusers=pgTable('users',{id: serial('id').primaryKey(),fullName: text('full_name').notNull(),phone: varchar('phone',{length: 20}).notNull(),role: text('role',{enum: ['user','admin']}).default('user').notNull(),cityId: integer('city_id').references(()=>cities.id),createdAt: timestamp('created_at').defaultNow().notNull(),updatedAt: timestamp('updated_at').defaultNow().notNull(),});exporttypeUser=InferModel<typeofusers>;exporttypeNewUser=InferModel<typeofusers,'insert'>;exportconstcities=pgTable('cities',{id: serial('id').primaryKey(),name: text('name').notNull(),});exporttypeCity=InferModel<typeofcities>;exporttypeNewCity=InferModel<typeofcities,'insert'>;constpool=newPool({connectionString: 'postgres://user:password@host:port/db',});constdb=drizzle(pool);// InsertconstnewUser: NewUser={fullName: 'John Doe',phone: '+123456789',};constinsertedUsers/* : User[] */=awaitdb.insert(users).values(newUser).returning();constinsertedUser=insertedUsers[0]!;constnewCity: NewCity={name: 'New York',};constinsertedCities/* : City[] */=awaitdb.insert(cities).values(newCity).returning();constinsertedCity=insertedCities[0]!;// UpdateconstupdateResult/* : { updated: Date }[] */=awaitdb.update(users).set({cityId: insertedCity.id,updatedAt: newDate()}).where(eq(users.id,insertedUser.id)).returning({updated: users.updatedAt});// SelectconstallUsers/* : User[] */=awaitdb.select().from(users);// Select custom fieldsconstupperCaseNames/* : { id: number; name: string }[] */=awaitdb.select({id: users.id,name: sql<string>`upper(${users.fullName})`,}).from(users);// Joins// You wouldn't BELIEVE how SMART the result type is! 😱constallUsersWithCities=awaitdb.select({id: users.id,name: users.fullName,city: {id: cities.id,name: cities.name,},}).from(users).leftJoin(cities,eq(users.cityId,cities.id));// DeleteconstdeletedNames/* : { name: string }[] */=awaitdb.delete(users).where(eq(users.id,insertedUser.id)).returning({name: users.fullName});See full docs for further reference: