Post ini merekomendasikan untuk memperkenalkan NestJS sekitar tanda 20–30 endpoint, atau ketika Anda membutuhkan WebSocket atau pekerjaan background. Route Handlers tidak menegakkan struktur, sehingga bisa menjadi tempat pembuangan begitu permukaan API Anda tumbuh melampaui CRUD sederhana dan webhook. Untuk proyek sampingan solo murni, Route Handlers dengan Prisma seringkali cukup dan NestJS bisa dilewati sepenuhnya.
Ya — post ini menjelaskan penggunaan Route Handlers sebagai proxy BFF tipis di depan NestJS. Route Handler memvalidasi sesi dengan Clerk atau Auth.js, mengekstrak ID pengguna, lalu memanggil API NestJS menggunakan token layanan internal. Ini menjaga API NestJS bersih dari urusan session cookie sambil tetap memberikan manfaat rendering Server Component pada frontend Next.js.
Keunggulannya adalah nol manajemen server, penskalaan otomatis ke nol, dan cold start biasanya di bawah 200ms untuk runtime Node.js. Kekurangannya adalah tidak ada memori persisten antar request, tidak ada dukungan WebSocket native, dan batas waktu eksekusi (10 detik di paket hobby, 60 detik di pro). Proses yang berjalan lama atau koneksi WebSocket membutuhkan server persisten seperti NestJS di VPS atau Cloud Run.
Dalam pengaturan Turborepo, Anda mendefinisikan tipe request dan response API sekali saja dalam paket packages/types bersama. Backend NestJS dan frontend Next.js sama-sama mengimpor dari paket yang sama, menghilangkan drift tipe, sinkronisasi manual, dan ketidakcocokan bentuk runtime. Post ini menyebut ini sebagai arsitektur yang digunakan untuk proyek komersial, dengan type safety ditegakkan di level monorepo.
Setup umum yang dijelaskan adalah Next.js di Vercel untuk frontend dan BFF Route Handlers, dipasangkan dengan NestJS di VPS seharga $6/bulan atau Cloud Run untuk API logika bisnis. Ini menjaga biaya infrastruktur tetap rendah sambil mempertahankan pemisahan yang bersih antara lapisan presentasi dan backend inti.
Saya menjalankan Next.js API Routes (sekarang Route Handlers) untuk logika backend yang ringan dan NestJS untuk layanan backend kompleks — kadang dalam proyek yang sama. Pertanyaan yang paling sering saya terima adalah: 'Kapan saya menggunakan NestJS vs hanya menambahkan Route Handler lain?' Jawabannya tergantung pada kompleksitas logika bisnis Anda, ukuran tim Anda, dan model deployment Anda.
| Dimensi | Next.js API Routes | NestJS |
|---|---|---|
| Overhead setup | Zero config, satu file jadi satu route | Module, controller, dan provider di-scaffold di awal |
| Dependency injection | Tidak ada bawaan, wiring manual | Container DI kelas satu sejak awal |
| Struktur saat scale | Bisa berubah jadi kumpulan handler yang longgar keterkaitannya | Arsitektur modular yang dipaksakan seiring codebase membesar |
| Model deployment | Deploy bersamaan dengan frontend | Deploy sebagai backend service yang independen |
| Testing | Setup manual untuk test level handler | Module testing bawaan dengan dependency mocking |
| Kecocokan ukuran tim | Developer solo dan tim kecil | Tim besar yang butuh konvensi yang dipaksakan |
| Paling cocok untuk | Logika backend ringan berdampingan dengan aplikasi frontend | Layanan backend kompleks dengan banyak aturan domain |
Route Handlers sangat baik untuk: pola BFF (Backend for Frontend) di mana Anda mengagregasikan data dari beberapa layanan untuk halaman tertentu, penerima webhook (Stripe, GitHub, Clerk), endpoint CRUD sederhana yang langsung memetakan ke query Prisma, dan handler callback Auth.js/NextAuth. Keunggulan utama adalah kolokasi — kode frontend dan backend Anda berbagi repo yang sama, konfigurasi TypeScript yang sama, dan variabel lingkungan yang sama.
Next.js Route Handlers di Vercel dideploy sebagai fungsi serverless. Ini berarti cold start nol untuk runtime Node.js (di bawah 200ms biasanya), penskalaan otomatis ke nol, dan tidak ada manajemen server. Trade-off: tidak ada memori persisten antar request, tidak ada WebSocket, dan batas waktu eksekusi. Untuk pola request-response sederhana, serverless adalah model yang tepat. Untuk proses yang berjalan lama atau koneksi WebSocket, Anda membutuhkan server persisten — dan di situlah NestJS berada.
Next.js Route Handler NestJS
──────────────────────── ─────────────────────────────
app/api/users/route.ts src/users/
├── users.module.ts
export async function GET() { ├── users.controller.ts
const users = await ├── users.service.ts
prisma.user.findMany() └── users.repository.ts
return Response.json(users)
} @Controller('users')
export class UsersController {
// Deployment: constructor(private usersService: UsersService) {}
// ↓ Vercel serverless function @Get()
// ↓ Cold start: ~200ms @UseGuards(JwtAuthGuard)
// ↓ Max execution: 60s async findAll() {
// ↓ No WebSockets return this.usersService.findAll()
// ↓ No persistent memory }
}
My production architecture: // Deployment:
┌─────────────────────┐ // ↓ VPS / Cloud Run / Railway
│ Next.js (Vercel) │ // ↓ Persistent memory
│ ├── Frontend pages │ // ↓ WebSocket gateways
│ └── BFF routes │──────► NestJS API (Railway/Cloud Run)
│ (session auth, │ // ↓ Bull job queues
│ aggregation) │ // ↓ Background workers
└─────────────────────┘Dari menjalankan Next.js Route Handlers dan NestJS di produksi: gunakan Next.js Route Handlers sebagai proxy tipis ke NestJS ketika Anda butuh data fetching SSR terintegrasi dengan logika backend Anda. Route Handler memvalidasi sesi, mengekstrak ID pengguna, dan memanggil API NestJS dengan token layanan internal. Pola ini menjaga API NestJS Anda bersih sementara memberikan manfaat rendering Server Component frontend Anda.
Arsitektur modul + controller + service + repository NestJS terasa verbose untuk CRUD sederhana. Di mana ia mendapat manfaat: logika bisnis kompleks dengan beberapa layanan yang perlu berbagi state, pipeline middleware yang diterapkan secara konsisten di seluruh route, WebSocket Gateway yang dikolokasikan dengan endpoint REST, dan dependency injection untuk pengujian. API NestJS dengan 50 endpoint lebih mudah dipelihara daripada 50 file Route Handler — struktur yang dipaksakan mencegah spaghetti yang tumbuh di basis kode yang tidak terstruktur.
# When does Next.js API Routes complexity break down?
# Example: 20+ endpoints with no structure
app/api/
├── users/route.ts # GET all, POST create
├── users/[id]/route.ts # GET one, PATCH, DELETE
├── users/[id]/roles/route.ts
├── products/route.ts
├── products/[id]/route.ts
├── orders/route.ts # complex business logic
├── orders/[id]/route.ts
├── orders/[id]/items/route.ts
├── invoices/route.ts # PDF generation, email triggers
└── ... # 30+ more files
# Problem: no shared guards, no DI for testing, no middleware pipeline
# NestJS equivalent (structured):
src/
├── users/
│ ├── users.module.ts
│ ├── users.controller.ts # HTTP handlers
│ ├── users.service.ts # business logic
│ └── users.service.spec.ts # easily mockable via DI
├── products/
│ └── ...
├── orders/
│ ├── orders.module.ts
│ ├── orders.controller.ts
│ ├── orders.service.ts
│ └── orders.processor.ts # Bull queue processor
└── app.module.ts
# Shared middleware across all routes:
@Module({ providers: [{ provide: APP_GUARD, useClass: JwtAuthGuard }] })
// Every route protected in one line — impossible with Route Handlers without boilerplateArgumen terkuat untuk combo Next.js + NestJS dalam monorepo adalah type TypeScript bersama. Dalam pengaturan Turborepo, Anda mendefinisikan tipe request/response API Anda dalam paket packages/types bersama. Backend NestJS dan frontend Next.js mengimpor dari tipe yang sama — tidak ada drift, tidak ada sinkronisasi manual, tidak ada ketidakcocokan bentuk runtime.
Saya telah melihat proyek Next.js di mana seluruh backend ERP diimplementasikan sebagai Route Handlers — ratusan file di app/api/, tidak ada logika bisnis bersama, validasi yang diduplikasi di mana-mana. Route Handlers tidak menegakkan struktur, sehingga tanpa disiplin mereka menjadi tempat pembuangan. Jika permukaan API Anda melebihi 20 endpoint, logika bisnis Anda non-trivial, atau Anda membutuhkan WebSocket atau pekerjaan background, investasikan di NestJS.
Next.js Route Handlers di Vercel mudah dideploy — tidak ada manajemen server. NestJS memerlukan server persisten: VPS, kontainer di Cloud Run/ECS, atau PaaS seperti Railway atau Render. Untuk sebagian besar proyek klien saya, arsitekturnya adalah: Next.js di Vercel (frontend + BFF Route Handlers) + NestJS di VPS $6/bulan atau Cloud Run (API logika bisnis). Ini menjaga biaya rendah sambil mempertahankan pemisahan yang tepat.
Stack default saya: Next.js untuk frontend dengan Route Handlers untuk logika BFF, NestJS untuk API backend utama. Saya mulai dengan hanya Next.js Route Handlers pada proyek baru untuk memvalidasi produk dengan cepat, lalu memperkenalkan NestJS ketika kompleksitas backend membenarkannya — biasanya sekitar tanda 20-30 endpoint atau ketika saya butuh WebSocket. Untuk proyek sampingan solo murni, Next.js Route Handlers dengan Prisma mencakup semua yang saya butuhkan.
Gunakan Next.js Route Handlers jika: (1) Anda pengembang solo atau tim 2 orang, (2) Deploy ke Vercel dan inginkan nol manajemen server, (3) Backend Anda adalah CRUD sederhana + webhook, (4) Anda menginginkan kolokasi dengan frontend. Gunakan NestJS jika: (1) Tim Anda memiliki pengembang backend khusus, (2) Anda membutuhkan WebSocket, pekerjaan background, atau middleware kompleks, (3) Permukaan API Anda memiliki 30+ endpoint dengan logika bisnis kompleks, (4) Anda butuh pengujian granular dengan mocking dependency injection.