Drizzle ORM — TypeScript ORM siêu nhẹ đang thay đổi cách viết SQL

Posted on: 4/27/2026 7:15:16 AM

~12KBBundle size (nhỏ hơn Prisma 130x)
0Dependencies
50msCold start trên Lambda
30K+GitHub Stars

1. Drizzle ORM là gì?

Drizzle ORM là một TypeScript ORM theo hướng SQL-first — nghĩa là bạn viết schema và query gần như giống SQL thuần, nhưng được bọc trong TypeScript với full type safety. Không có query engine riêng, không có binary Rust, không có bước code generation — tất cả đều là TypeScript thuần từ đầu đến cuối.

Trong khi Prisma chọn cách trừu tượng hoá SQL phía sau một DSL riêng (.prisma schema), Drizzle đi ngược lại: giữ nguyên SQL mental model nhưng thêm type safety và developer experience hiện đại. Triết lý là: "Nếu bạn biết SQL, bạn đã biết Drizzle."

Tại sao Drizzle nổi lên năm 2026?

Sự bùng nổ của edge computing (Cloudflare Workers, Vercel Edge Functions) đặt ra yêu cầu khắt khe về bundle size và cold start. Prisma 5.x với Rust query engine nặng ~13MB gần như không thể deploy lên edge. Drizzle với ~12KB runtime trở thành lựa chọn tự nhiên cho edge-first applications.

2. Kiến trúc: Tại sao Drizzle nhỏ đến vậy?

graph TB
    subgraph Prisma["Prisma Architecture"]
        PA["Schema DSL
(.prisma file)"] -->|"prisma generate"| PB["Generated Client
+ Types"] PB --> PC["TypeScript/WASM
Query Engine ~1.6MB"] PC --> PD["Database Driver"] end subgraph Drizzle["Drizzle Architecture"] DA["TypeScript Schema
(tables, columns)"] -->|"Direct import"| DB["Query Builder
~12KB total"] DB --> DC["Database Driver"] end PD --> E["PostgreSQL / MySQL
SQLite / SQL Server"] DC --> E style PA fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50 style PB fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50 style PC fill:#ff9800,stroke:#fff,color:#fff style PD fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50 style DA fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style DB fill:#e94560,stroke:#fff,color:#fff style DC fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style E fill:#2c3e50,stroke:#fff,color:#fff
Prisma có thêm lớp Query Engine, Drizzle sinh SQL trực tiếp từ TypeScript

Drizzle bỏ hoàn toàn lớp trung gian. Schema được định nghĩa bằng TypeScript thuần — pgTable(), mysqlTable(), sqliteTable() — trình query builder đọc schema này và sinh ra SQL string tương ứng. Không có bước generate, không có file trung gian, types luôn đồng bộ với source code.

3. Định nghĩa Schema — Code-first bằng TypeScript

Một trong những điểm mạnh nhất của Drizzle: schema là TypeScript code thực sự, không phải DSL riêng.

// schema.ts — Drizzle schema definition
import { pgTable, serial, text, integer, timestamp, boolean } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: text('email').notNull().unique(),
  name: text('name').notNull(),
  avatarUrl: text('avatar_url'),
  isActive: boolean('is_active').default(true),
  createdAt: timestamp('created_at').defaultNow(),
});

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  content: text('content'),
  authorId: integer('author_id')
    .notNull()
    .references(() => users.id),
  publishedAt: timestamp('published_at'),
  viewCount: integer('view_count').default(0),
});

// Types được infer tự động — không cần generate
type User = typeof users.$inferSelect;
type NewUser = typeof users.$inferInsert;

So sánh với Prisma schema tương đương:

// schema.prisma — Prisma DSL
model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String
  avatarUrl String?  @map("avatar_url")
  isActive  Boolean  @default(true) @map("is_active")
  createdAt DateTime @default(now()) @map("created_at")
  posts     Post[]

  @@map("users")
}

model Post {
  id          Int       @id @default(autoincrement())
  title       String
  content     String?
  authorId    Int       @map("author_id")
  author      User      @relation(fields: [authorId], references: [id])
  publishedAt DateTime? @map("published_at")
  viewCount   Int       @default(0) @map("view_count")

  @@map("posts")
}
// Sau đó phải chạy: npx prisma generate

Ưu điểm code-first

Vì schema là TypeScript, bạn có thể dùng mọi tính năng của ngôn ngữ: chia schema thành nhiều file, import/export, conditional logic, shared utilities. Không bị giới hạn bởi syntax của một DSL riêng.

4. Query Builder — SQL mà bạn đã biết

Drizzle query builder map gần như 1:1 với SQL syntax. Nếu biết viết SQL, bạn biết viết Drizzle.

import { db } from './db';
import { users, posts } from './schema';
import { eq, gt, desc, sql, and, like } from 'drizzle-orm';

// SELECT cơ bản
const allUsers = await db.select().from(users);

// WHERE + ORDER BY
const activeUsers = await db
  .select()
  .from(users)
  .where(eq(users.isActive, true))
  .orderBy(desc(users.createdAt));

// JOIN
const usersWithPosts = await db
  .select({
    userName: users.name,
    postTitle: posts.title,
    views: posts.viewCount,
  })
  .from(users)
  .innerJoin(posts, eq(users.id, posts.authorId))
  .where(gt(posts.viewCount, 100));

// INSERT returning
const [newUser] = await db
  .insert(users)
  .values({ email: 'dev@example.com', name: 'Dev' })
  .returning();

// UPDATE
await db
  .update(posts)
  .set({ viewCount: sql`${posts.viewCount} + 1` })
  .where(eq(posts.id, 42));

// Subquery
const topAuthors = await db
  .select({
    name: users.name,
    totalViews: sql<number>`sum(${posts.viewCount})`.as('total_views'),
  })
  .from(users)
  .innerJoin(posts, eq(users.id, posts.authorId))
  .groupBy(users.name)
  .having(gt(sql`sum(${posts.viewCount})`, 1000))
  .orderBy(desc(sql`total_views`));

5. Relational Queries — Khi cần API style

Bên cạnh SQL-style query builder, Drizzle cũng cung cấp Relational Query API cho những ai thích Prisma-style nested queries:

import { relations } from 'drizzle-orm';

// Định nghĩa relations
export const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));

// Query với nested relations — giống Prisma
const result = await db.query.users.findMany({
  with: {
    posts: {
      where: gt(posts.viewCount, 50),
      orderBy: desc(posts.publishedAt),
      limit: 5,
    },
  },
  where: eq(users.isActive, true),
});

6. So sánh Hiệu năng: Drizzle vs Prisma 7

Tiêu chíDrizzle 0.45.xPrisma 7.xPrisma 5.x (cũ)
Bundle size~12KB~1.6MB (600KB gzip)~13MB
Cold start (Lambda)50-100ms80-150ms600-1800ms
Simple query overhead0.5-1ms1-2ms3-5ms
Complex join overhead1-3ms2-5ms5-10ms
Code generationKhông cầnCần prisma generateCần
Dependencies0NhiềuNhiều + Rust binary
Tree-shakeableMột phầnKhông

Benchmark trong bối cảnh thực tế

Chênh lệch query overhead (0.5ms vs 2ms) hiếm khi là bottleneck. Database round-trip latency thường là 5-50ms — ORM overhead chỉ chiếm 2-10% tổng thời gian. Drizzle thực sự vượt trội ở bundle sizecold start — hai yếu tố sống còn trên edge và serverless.

7. Migration — Hai chế độ linh hoạt

Drizzle Kit cung cấp hai workflow migration:

7.1 Generate + Migrate (Production)

# Sinh file migration SQL từ schema changes
npx drizzle-kit generate --name add_user_avatar

# Xem SQL sẽ được chạy
cat drizzle/0001_add_user_avatar.sql

# Áp dụng migration
npx drizzle-kit migrate

7.2 Push (Prototyping)

# Đẩy schema trực tiếp lên DB, không tạo migration file
npx drizzle-kit push

# Phù hợp cho development nhanh, KHÔNG dùng cho production

7.3 Drizzle Studio — GUI quản lý data

# Mở web UI để browse và edit data
npx drizzle-kit studio

Drizzle Studio chạy trên browser, hỗ trợ xem schema, query data, edit record trực tiếp — tương tự Prisma Studio nhưng không cần cài đặt riêng.

8. Database Support

DatabaseDriverEdge-compatible
PostgreSQLpostgres, pg, @neondatabase/serverlessNeon, Supabase
MySQLmysql2, @planetscale/databasePlanetScale
SQLitebetter-sqlite3, @libsql/clientTurso, Cloudflare D1
SQL ServerCommunity driverHạn chế
Gel (mới)Gel dialect riêngĐang phát triển

Edge Database tối ưu

Kết hợp Drizzle + Turso (libSQL trên edge) hoặc Drizzle + Cloudflare D1 cho database layer hoàn toàn trên edge — zero latency đến database, cold start gần như tức thời. Đây là stack mà nhiều startup đang chọn năm 2026.

9. Tích hợp với Vue.js và Nuxt

Drizzle hoạt động hoàn hảo trong Nuxt server routesVue full-stack apps:

// server/utils/db.ts — Nuxt 4 server utility
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from '~/server/db/schema';

const client = postgres(process.env.DATABASE_URL!);
export const db = drizzle(client, { schema });

// server/api/posts.get.ts — API route
export default defineEventHandler(async () => {
  return db.query.posts.findMany({
    with: { author: true },
    where: eq(schema.posts.publishedAt, sql`IS NOT NULL`),
    orderBy: desc(schema.posts.publishedAt),
    limit: 20,
  });
});

10. Khi nào chọn Drizzle, khi nào chọn Prisma?

graph TD
    A["Chọn TypeScript ORM"] --> B{"Deploy lên edge?
Bundle size quan trọng?"} B -->|"Có"| C["✅ Drizzle"] B -->|"Không"| D{"Team quen SQL?"} D -->|"Có"| E["✅ Drizzle"] D -->|"Không, muốn
abstraction cao"| F["✅ Prisma"] A --> G{"Cần ecosystem
mạnh (Studio,
Accelerate)?"} G -->|"Có"| H["✅ Prisma"] G -->|"Không, cần
nhẹ và nhanh"| I["✅ Drizzle"] style A fill:#2c3e50,stroke:#fff,color:#fff style C fill:#e94560,stroke:#fff,color:#fff style E fill:#e94560,stroke:#fff,color:#fff style F fill:#4CAF50,stroke:#fff,color:#fff style H fill:#4CAF50,stroke:#fff,color:#fff style I fill:#e94560,stroke:#fff,color:#fff style B fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50 style D fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50 style G fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50
Decision tree: Drizzle vs Prisma tuỳ theo context dự án
✅ Chọn Drizzle✅ Chọn Prisma
Deploy edge / serverless (bundle nhỏ)Team mới với SQL, cần abstraction
Team thành thạo SQLDự án lớn cần ecosystem mạnh
Không muốn bước code generationThích schema DSL rõ ràng
Cần tree-shaking tối đaCần Prisma Accelerate (connection pooling)
Đa database backendTeam quen Prisma workflow

11. Quick Start — 5 phút với Drizzle

# Cài đặt
npm install drizzle-orm postgres
npm install -D drizzle-kit

# Tạo config
# drizzle.config.ts
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  schema: './src/schema.ts',
  out: './drizzle',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});

# Tạo schema, push lên DB, bắt đầu code
npx drizzle-kit push
npx drizzle-kit studio  # Mở GUI

12. Kết luận

Drizzle ORM đại diện cho một thế hệ công cụ mới: nhẹ, type-safe, SQL-first, và tối ưu cho thời đại edge computing. Với bundle size chỉ 12KB, zero dependencies, và cold start nhanh gấp đôi Prisma, Drizzle là lựa chọn tự nhiên cho các dự án cần deploy trên Cloudflare Workers, Vercel Edge, hay bất kỳ môi trường serverless nào.

Prisma vẫn là ORM mạnh mẽ với ecosystem đồ sộ — đặc biệt sau khi Prisma 7 loại bỏ Rust engine. Nhưng nếu bạn muốn một ORM "nghĩ cùng bạn" thay vì "nghĩ thay bạn", Drizzle xứng đáng được thử.

Bắt đầu từ đâu?

Nếu dùng Nuxt/Vue: tham khảo Drizzle Quick Start + setup server/utils/db.ts. Nếu dùng Node.js thuần: npm install drizzle-orm postgres và bắt đầu định nghĩa schema. Toàn bộ quá trình từ install đến query đầu tiên mất khoảng 5 phút.

Nguồn tham khảo: