Production deployment Drizzle ORM: database connection management untuk serverless dan traditional, migration strategy dengan generate + review + apply via CI/CD, performance monitoring dengan EXPLAIN ANALYZE dan slow query logging, security best practice, CI/CD integration, dan health check endpoint untuk memverifikasi koneksi database.

Setelah di episode 19 kita mempelajari Project Structure & Scalability — modular schema, query service pattern, dan scaling ke microservices — pada episode ini — episode terakhir — kita menutup series dengan production deployment: bagaimana menjalankan Drizzle ORM di production dengan aman, scalable, dan reliable.
Production deployment berbeda dari development: connection management lebih kritis, migration harus terkontrol, performance harus dimonitor, dan keamanan harus diutamakan.
import { drizzle } from 'drizzle-orm/neon-http'
import { neon } from '@neondatabase/serverless'
const sql = neon(process.env.DATABASE_URL!)
export const db = drizzle(sql)Serverless tidak membutuhkan connection pooling — driver handles. Neon, Turso, dan D1 sudah dioptimasi untuk request-response pattern.
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
const client = postgres(process.env.DATABASE_URL!, {
max: 20,
idle_timeout: 20,
})
export const db = drizzle(client)Connection pool memastikan koneksi di-reuse, tidak dibuat baru setiap request.
# 1. Update schema TypeScript
# 2. Generate migration
npx drizzle-kit generate
# 3. Review generated SQL
cat drizzle/0001_add_column.sql
# 4. Apply via CI/CD
npx drizzle-kit migrateJika migration gagal:
Jangan edit migration files yang sudah di-apply — buat migration baru untuk perubahan apapun.
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = 'john@example.com';Pastikan query menggunakan index, bukan sequential scan.
# postgresql.conf
log_min_duration_statement = 100 # Log queries > 100msIdentifikasi query yang lambat dan optimasi dengan index.
EXPLAIN SELECT * FROM users WHERE email = 'john@example.com';
-- Pastikan: Index Scan, bukan Seq ScanDrizzle ORM sudah menggunakan prepared statements secara default — aman dari SQL injection. Tidak perlu khawatir.
CREATE USER app_user WITH PASSWORD 'secure_password';
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;
-- Jangan grant DROP, ALTER, atau CREATE untuk app userDatabase user hanya punya permissions yang dibutuhkan — tidak lebih.
# Jangan hardcode! Gunakan environment variables
DATABASE_URL=postgresql://user:password@host:5432/dbDi production, gunakan secret manager (AWS Secrets Manager, Vercel Environment Variables, Cloudflare Secrets).
name: Deploy
on:
push:
branches: [main]
jobs:
migrate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx drizzle-kit generate
- run: npx drizzle-kit migrate
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
deploy:
needs: [migrate]
runs-on: ubuntu-latest
steps:
- run: npm run build
- run: ./deploy.shimport { sql } from 'drizzle-orm'
app.get('/health', async (c) => {
try {
await db.execute(sql`SELECT 1`)
return c.json({ status: 'healthy', database: 'connected' })
} catch (error) {
return c.json({ status: 'unhealthy', database: 'disconnected' }, 503)
}
})Health check memverifikasi bahwa aplikasi bisa terhubung ke database — kritis untuk load balancer dan orchestrator (Kubernetes, ECS).
Warning
Health check endpoint harus cepat dan tidak mengembalikan data sensitif. Cukup SELECT 1 untuk memverifikasi koneksi. Jangan log query di health check — ini akan membanjiri logs dengan false positives.
Sepanjang 21 episode, kita telah menempuh perjalanan lengkap Drizzle ORM dari fondasi hingga production:
Drizzle ORM adalah tool yang ringan, powerful, dan TypeScript-native. Dengan pemahaman yang solid tentang konsep-konsep ini, kalian bisa membangun database layer yang scalable, maintainable, dan production-ready. Selamat menempuh perjalanan ini, dan semoga kalian bisa memanfaatkan Drizzle ORM secara optimal di proyek kalian!