Mengintegrasikan Drizzle ORM ke proyek ElysiaJS: setup driver SQLite atau PostgreSQL, mendefinisikan schema Drizzle, query builder yang type-safe, serta membuat database plugin untuk akses dari semua route.

Setelah di episode 7 kita memahami plugin system, pada episode ini kita akan mengintegrasikan database ke proyek ElysiaJS menggunakan Drizzle ORM — TypeScript-first ORM yang ringan (~7KB), zero dependencies, dan kompatibel dengan runtime Bun.
Keduanya dibangun dengan filosofi yang sama: TypeScript-first, performa tinggi, dan minimalis. Drizzle menggunakan SQL-like query builder yang familiar, sementara ElysiaJS memastikan tipe dari query secara otomatis terekspos ke route handler.
bun add drizzle-orm
bun add -D drizzle-kitPilih driver sesuai database kalian:
bun add @libsql/client # Turso/SQLite
bun add postgres # PostgreSQL
bun add mysql2 # MySQLimport { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
email: text('email').notNull().unique(),
createdAt: text('created_at').notNull().default(''),
})
export const posts = sqliteTable('posts', {
id: integer('id').primaryKey({ autoIncrement: true }),
title: text('title').notNull(),
content: text('content').notNull(),
authorId: integer('author_id').notNull().references(() => users.id),
})import { drizzle } from 'drizzle-orm/bun-sqlite'
import { Database } from 'bun:sqlite'
import * as schema from './schema'
const sqlite = new Database('local.db')
export const db = drizzle(sqlite, { schema })Drizzle menyediakan SQL-like API yang type-safe:
import { Elysia, t } from 'elysia'
import { db } from './db'
import { users } from './db/schema'
import { eq } from 'drizzle-orm'
const app = new Elysia()
.get('/users', async () => {
return await db.select().from(users)
})
.get('/users/:id', async ({ params }) => {
const [user] = await db.select().from(users).where(eq(users.id, Number(params.id)))
return user ?? { error: 'Not found' }
}, {
params: t.Object({ id: t.String() })
})
.post('/users', async ({ body }) => {
const [created] = await db.insert(users).values(body).returning()
return created
}, {
body: t.Object({
name: t.String(),
email: t.String({ format: 'email' }),
})
})
.listen(3000)Untuk menjaga dependency tetap bersih, buat database plugin:
import { Elysia } from 'elysia'
import { drizzle } from 'drizzle-orm/bun-sqlite'
import { Database } from 'bun:sqlite'
import * as schema from '../db/schema'
export const dbPlugin = (app: Elysia) => {
const sqlite = new Database('local.db')
const db = drizzle(sqlite, { schema })
return app.decorate('db', db).onStop(() => {
sqlite.close()
})
}import { dbPlugin } from './plugins/database'
const app = new Elysia()
.use(dbPlugin)
.get('/users', async ({ db }) => {
return await db.select().from(users)
})
.listen(3000)Untuk database remote (PostgreSQL, MySQL), gunakan connection pooling:
import { drizzle } from 'drizzle-orm/node-postgres'
import { Pool } from 'pg'
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
max: 20,
})
export const db = drizzle(pool)Warning
Untuk SQLite di Bun, tidak ada connection pooling — satu koneksi cukup karena SQLite menggunakan file-based locking. Untuk PostgreSQL atau MySQL, selalu gunakan connection pooling untuk performa production.
Pada episode 8 ini, kalian telah mengintegrasikan Drizzle ORM ke proyek ElysiaJS — dari setup hingga query builder type-safe dan database plugin.
Inti yang harus dibawa pulang:
drizzle-orm, driver database, dan drizzle-kit.sqliteTable() atau pgTable().db.select(), db.insert(), db.update(), db.delete().Di episode 9 selanjutnya kita akan memahami Eden Treaty: end-to-end type safety — setup Eden client, type inference di client, dan kapan pakai Eden vs REST client biasa. Sampai jumpa di episode 9!