Kysely: Giải pháp Query Builder thay thế Prisma và TypeORM cho dự án TypeScript

Development tutorial - IT technology blog
Development tutorial - IT technology blog

Sự cố nhớ đời: Khi Prisma khiến server “bay màu” 1GB RAM

2 giờ sáng, điện thoại mình rung liên hồi. Hệ thống monitoring báo động đỏ: Memory Usage trên các instance Node.js vọt lên 95%, latency chạm ngưỡng 5 giây. Sau khi kiểm tra log, mình nhận ra thủ phạm là Prisma Client. Với schema hơn 50 table và các câu query include lồng nhau, Prisma engine (viết bằng Rust) ngốn tài nguyên khủng khiếp để map dữ liệu.

Dự án tiếp theo với 5 developer, mình quyết định thay đổi hoàn toàn stack: Loại bỏ ORM cồng kềnh và chuyển sang Kysely. Kết quả thật bất ngờ. Productivity của team tăng rõ rệt. Code chạy nhanh hơn, và quan trọng nhất, lỗi runtime liên quan đến database gần như biến mất.

Tại sao Prisma hay TypeORM dần trở thành rào cản?

Prisma rất tuyệt cho người mới vì nó che giấu sự phức tạp của SQL. Tuy nhiên, khi dự án scale, bạn sẽ vấp phải những vấn đề thực tế sau:

  • Runtime Overhead: Prisma chạy một query engine riêng dưới dạng sidecar process. Trên AWS Lambda, điều này khiến Cold Start tăng từ 200ms lên tận 2-3 giây.
  • Khó tối ưu: Việc viết Common Table Expressions (CTE) hay Window Functions trong Prisma là một cực hình. Bạn thường phải fallback về $queryRaw và mất sạch tính năng type-safe.
  • Type-safety lỏng lẻo: TypeORM dựa nặng vào Decorators. Chỉ cần quên một cái @Entity(), lỗi sẽ chỉ xuất hiện khi code đã chạy trên production.

Kysely – Sự giao thoa giữa SQL thuần túy và TypeScript

Kysely không phải là ORM. Nó là một Type-safe SQL Query Builder. Thay vì cố biến các hàng trong database thành các object phức tạp, nó giúp bạn viết SQL trực tiếp bằng TypeScript.

Ưu thế lớn nhất của Kysely là Zero Runtime Overhead. Nó chỉ đơn thuần là một công cụ build string SQL thông minh. Bundle size của nó chỉ khoảng vài chục KB, so với con số hàng chục MB của Prisma engine.

Cài đặt và cấu hình thực tế

Nếu bạn dùng PostgreSQL, hãy cài đặt các package sau:

npm install kysely pg
npm install -D @types/pg

Thay vì để ORM tự suy diễn, chúng ta định nghĩa rõ ràng cấu trúc table qua interface. Đây là “nguồn chân lý” duy nhất cho toàn bộ app:

import { Generated, ColumnType } from 'kysely'

interface UserTable {
  id: Generated<number>
  email: string
  first_name: string | null
  created_at: ColumnType<Date, string | undefined, never>
}

export interface Database {
  users: UserTable
  posts: { id: Generated<number>; title: string; author_id: number }
}

Kinh nghiệm thực tế: Đừng gõ tay nếu DB có 100 table. Hãy dùng kysely-codegen để quét schema DB và tự sinh ra các interface này trong 1 nốt nhạc.

Khởi tạo Kysely instance

Việc setup kết nối rất gọn gàng:

import { Pool } from 'pg'
import { Kysely, PostgresDialect } from 'kysely'
import { Database } from './types'

const db = new Kysely<Database>({
  dialect: new PostgresDialect({
    pool: new Pool({ connectionString: process.env.DATABASE_URL }),
  }),
})

Trải nghiệm Code: Khi TypeScript hiểu rõ SQL của bạn

Sức mạnh thực sự xuất hiện khi bạn gõ db.selectFrom(...). IDE sẽ gợi ý chính xác tên table, tên column và kiểu dữ liệu tương ứng. Bạn sẽ không bao giờ gặp lỗi gõ nhầm tên cột nữa.

Ví dụ Select và Join phức tạp

async function getPostsWithAuthors() {
  return await db
    .selectFrom('posts')
    .innerJoin('users', 'users.id', 'posts.author_id')
    .select([
      'posts.id',
      'posts.title',
      'users.first_name as author_name'
    ])
    .where('posts.title', 'like', '%TypeScript%')
    .execute()
}

Nếu bạn đổi tên column trong DB mà không cập nhật interface, TypeScript sẽ báo lỗi đỏ lòm ngay lập tức. Bạn biết chắc chắn code mình sẽ chạy đúng trước khi deploy.

Tại sao mình chọn Kysely cho dự án Production?

Sau 6 tháng chạy thực tế, mình rút ra 3 ưu điểm vượt trội:

  1. Kiểm soát tuyệt đối: Mình biết chính xác câu SQL nào đang thực thi. Việc tối ưu Index hay giải quyết vấn đề N+1 trở nên minh bạch hơn bao giờ hết.
  2. Tốc độ thực thi: Query thực hiện trực tiếp, không qua các tầng trung gian phức tạp. Latency giảm trung bình 30% so với khi dùng Prisma.
  3. Hỗ trợ SQL nâng cao: Kysely xử lý cực tốt JSONB của Postgres, Window Functions hay Subqueries mà không cần dùng đến chuỗi string thuần không an toàn.

Lời kết: Khi nào bạn nên chuyển đổi?

Nếu bạn đang làm dự án nhỏ (MVP) cần tốc độ mì ăn liền, Prisma vẫn rất ổn. Nhưng nếu bạn xây dựng hệ thống High-load, Serverless, hoặc đơn giản là muốn làm chủ hoàn toàn mã nguồn, Kysely là lựa chọn không thể bỏ qua.

Đầu tư thêm 15 phút setup ban đầu sẽ giúp bạn tránh được những cuộc gọi lúc nửa đêm. Kysely chính là điểm giao thoa lý tưởng giữa sức mạnh của SQL và sự an toàn của TypeScript.

Share: