Nextjs Instrumentation Middleware Auth Pattern Edge Node Runtime Selection
Selesai membaca dokumentasi ini?
Kembali ke rujukan utama Next.js untuk melanjutkan topik lainnya.
Kembali ke rujukan utama Next.js untuk melanjutkan topik lainnya.
Tiga mekanisme yang sering bertemu di aplikasi Next.js production, tapi punya peran berbeda:
edge atau nodejs.Ketiganya beririsan di satu titik: runtime yang dipakai menentukan API apa yang boleh kamu panggil. Salah pilih, gejalanya baru muncul di build atau production, bukan di local.
Pakai instrumentation kalau kamu butuh sesuatu berjalan sekali saat startup server, bukan per request.
Contoh yang masuk akal:
Jangan pakai instrumentation kalau:
Aturan praktis: sekali di startup, bukan per request → instrumentation. Per request → middleware/route.
File instrumentation.ts (atau instrumentation.js) ditaruh di root project, atau di dalam src/ kalau project pakai src/. Next.js memanggil fungsi register() yang diekspor saat server instance boot.
// instrumentation.ts
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
// hanya jalan di Node runtime
const { setupObservability } = await import('./lib/observability')
await setupObservability()
}
if (process.env.NEXT_RUNTIME === 'edge') {
// setup ringan khusus edge, misalnya edge cache client
}
}Yang perlu diperhatikan:
register() boleh async. Next.js menunggunya selesai sebelum mulai menerima request.register() jalan terpisah untuk tiap runtime. Instance Edge dan instance Node masing-masing manggil register(). Makanya guard NEXT_RUNTIME penting.experimental.instrumentationHook: true di next.config.instrumentation.node.ts dan instrumentation.edge.ts, masing-masing punya register() sendiri tanpa perlu guard manual.Alur startup:
Guard middleware bertugas memutuskan sebelum request sampai ke route: ada token/session yang valid atau tidak. Kalau tidak, redirect ke login (atau kembalikan 401 untuk API).
Kunci supaya guard ini aman di Edge Runtime: verifikasi token secara stateless pakai Web Crypto, bukan library Node. jose adalah pilihan yang tepat karena memakai Web Crypto API sehingga jalan di Edge. jsonwebtoken tidak bisa dipakai di middleware karena butuh Node crypto.
// middleware.ts (root project, atau src/middleware.ts)
import { NextResponse, type NextRequest } from 'next/server'
import { jwtVerify } from 'jose'
const secret = new TextEncoder().encode
Alur keputusan guard:
401, bukan redirect, supaya client tidak ikut tersesat./login jangan ke-trigger guard).export const runtime = 'edge' | 'nodejs'. Default nodejs.// app/api/protected/route.ts
export const runtime = 'nodejs' // bisa diganti 'edge'
export async function GET() {
// ...
}| Aspek | Edge Runtime | Node.js Runtime |
|---|---|---|
| Lokasi eksekusi | Dekat user (edge network) | Server/node standar |
| Cold start | Sangat kecil | Lebih besar |
| API Node | Terbatas | Lengkap |
Web Crypto (jose, crypto.subtle) | Didukung | Didukung |
fs, path, native module | Tidak | Ya |
DB driver berat (Prisma, pg) | Tidak | Ya |
| Cocok untuk | guard ringan, geolocation, redirect | query DB, file, library ekosistem Node |
fs, path, atau native moduleAlur request ke runtime:
jsonwebtoken di middlewarejsonwebtoken butuh Node crypto, sedangkan middleware jalan di Edge. Hasilnya: error saat build atau runtime. Solusi: pakai jose (Web Crypto).
bcrypt, pg, prisma, mongoose, atau apa pun yang butuh native module / Node API akan gagal di Edge. Middleware bukan tempatnya. Pindahkan ke route handler Node.
register() tanpa guard runtimeregister() jalan di Edge dan Node. Kalau kamu buka koneksi DB atau init SDK Node-only tanpa mengecek NEXT_RUNTIME, instance Edge akan crash. Selalu guard dengan if (process.env.NEXT_RUNTIME === 'nodejs').
Middleware berjalan di Edge yang tidak punya driver DB Node. Kalau butuh data user, verifikasi token di edge lalu delegasikan lookup ke route handler Node.
runtime = 'edge' di route handler tapi pakai fs / native moduleMenyetel export const runtime = 'edge' lalu memanggil fs.readFile atau require native akan gagal. Pastikan kode di route tersebut benar-benar edge-safe, atau biarkan default nodejs.
Kadang kamu tidak import bcrypt langsung, tapi sebuah modul shared (misalnya lib/auth) diam-diam mengimpor bcrypt atau pg. Saat middleware mengimpor lib/auth, seluruh chain ikut masuk Edge dan build gagal. Solusi: pisahkan modul edge-safe (lib/auth-edge pakai jose) dari modul Node (lib/auth-node).
Edge memberi cold start kecil, tapi kalau guard middleware melakukan fetch eksternal, loop, atau komputasi mahal, manfaat latency hilang. Guard harus singkat dan deterministik.
Skenario: user buka /dashboard di aplikasi production.
/dashboard/:path*.token, verifikasi signature pakai jose (Web Crypto)./login (dan /login di-exclude dari matcher, tidak loop).NextResponse.next(), request lanjut ke route./dashboard jalan di Node runtime, query data user dari DB.instrumentation.register() sudah jalan sekali saat server boot untuk menyiapkan tracing.matcher middleware sesempit mungkin. Matcher luas = biaya per request naik untuk semua request.AUTH_SECRET dibaca di server (middleware jalan di server/edge, bukan browser).jose untuk verifikasi di edge, jsonwebtoken hanya di Node. Jangan campur.instrumentation.ts: inisialisasi observability dan side-effect sekali jalan saat startup.jose: verifikasi JWT edge-safe lewat Web Crypto.next.config: experimental.instrumentationHook (untuk Next.js di bawah 15).