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.
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.