Vercel Functions adalah kode server yang kamu deploy bersama aplikasi Next.js di Vercel, dan tiap function memilih satu dari dua runtime: Node.js (Node lengkap, jalan di satu region yang kamu pilih) atau Edge (V8 isolate seperti Cloudflare Workers, kecil, jalan dekat pengunjung). Middleware adalah kode yang jalan sebelum request sampai ke halaman mana pun. Bayangin perumahan dengan satpam di gerbang dan kantor pengelola di dalam. Satpam memeriksa tiap tamu dengan cepat: gak punya kartu akses? Arahkan ke kantor untuk daftar. Tamu dari blok Indonesia? Arahkan ke papan petunjuk berbahasa Indonesia. Tapi satpam gak bisa membuka lemari arsip; urusan berkas tetap di kantor pengelola. Middleware dan Edge adalah satpamnya, function Node.js adalah kantornya.
🧪 Tebakan cepat: browser meminta
/_next/static/chunks/main.js. Apakah middleware di bawah ini ikut jalan untuk request itu? Tebak dulu, jawabannya ada di bagian "Matcher: request mana yang lewat middleware".
Dua runtime di Vercel
Frontend catatan-api, catatan-web, dipindah ke Next.js di Vercel, di https://app.catatan.example.com. Function-nya bisa memakai dua runtime:
| Node.js | Edge | |
|---|---|---|
| Mesin | Node.js lengkap | V8 isolate, Web API saja |
| Jalan di mana | region yang dipilih (bawaan proyek baru: iad1, Washington D.C.) |
region terdekat dengan pengunjung |
fs, child_process, modul native |
ada | gak ada |
| Cocok untuk | query database, olah file, kerja berat | redirect, cek cookie, A/B testing, geolocation |
Per 2025, Vercel sendiri menyarankan runtime Node.js untuk kebanyakan function, dan Edge untuk kerja kecil yang harus dekat pengunjung, terutama middleware.
Middleware: satpam di depan semua halaman
// middleware.ts (Next.js 13 sampai 15; di Next.js 16 namanya proxy.ts)
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// 1. Dashboard wajib login
const session = request.cookies.get("session");
if (!session && pathname.startsWith("/dashboard")) {
return NextResponse.redirect(new URL("/login", request.url));
}
// 2. Pengunjung dari Indonesia dapat halaman versi /id
const country = request.headers.get("x-vercel-ip-country") ?? "US";
if (country === "ID" && !pathname.startsWith("/id")) {
return NextResponse.rewrite(new URL(`/id${pathname}`, request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ["/((?!_next|static|favicon.ico).*)"],
};
NextResponse.redirect(url): browser disuruh pindah alamat, dengan status307dan headerlocation. Alamat di address bar berubah jadi/login.NextResponse.rewrite(url): Vercel diam-diam menyajikan halaman lain. Address bar tetap/, isinya dari/id/.NextResponse.next(): lanjut ke halaman yang diminta, tanpa perubahan.x-vercel-ip-countryadalah header yang ditambahkan Vercel berisi kode negara pengunjung (ID,US,SG). Helpergeolocation(request)dari paket@vercel/functionsmembaca header yang sama.- Urutannya penting: cek login dulu, baru negara. Kalau terbalik, pengunjung Indonesia tanpa session yang membuka
/dashboarddi-rewrite ke/id/dashboarddan pemeriksaan login gak pernah sampai.
Pengunjung dari Amerika tanpa cookie session yang membuka /dashboard/settings dapat redirect 307 ke /login.
Matcher: request mana yang lewat middleware
Middleware jalan untuk tiap request yang cocok dengan matcher. Next.js mengubah pola "/((?!_next|static|favicon.ico).*)" jadi regular expression: semua path, kecuali yang diawali _next, static, atau favicon.ico. Hasil di Lab (pengunjung dari Amerika, tanpa session):
| Path | Lewat middleware? | Hasil |
|---|---|---|
/ |
ya | next(), halaman utama |
/dashboard/settings |
ya | redirect 307 ke /login |
/catatan/42 |
ya | next() |
/_next/static/chunks/main.js |
tidak | file JavaScript langsung dikirim |
/favicon.ico |
tidak | ikon langsung dikirim |
Jadi middleware gak jalan untuk /_next/static/chunks/main.js. Itu jawaban tebakannya. Mengecualikan file statis menghemat waktu tiap request dan biaya, karena tiap kali middleware jalan dihitung sebagai pemanggilan.
Edge API route: export const runtime = "edge"
Di App Router, satu baris di file route memilih runtime-nya:
// app/api/hello/route.ts
export const runtime = "edge"; // deploy ke edge network, bukan sebagai function Node.js
export async function GET(request: Request) {
return Response.json({
message: "Hello from edge!",
region: process.env.VERCEL_REGION,
});
}
runtime = "edge": route ini di-deploy ke edge network dan jalan di V8 runtime yang sama dengan Cloudflare Workers. Tanpa baris itu, bawaannya"nodejs".process.env.VERCEL_REGIONberisi region yang menjalankannya. Dari Jakarta, function Edge jalan disin1(Singapura), region Vercel terdekat.
Region: dekat user atau dekat data
Waktu bolak-balik contoh dari Jakarta (sama dengan pelajaran Cloud Computing Basics): Singapura 20 ms, Virginia 230 ms.
/api/hello jalan sebagai |
Jalan di | Waktu ke pengunjung Jakarta (contoh) |
|---|---|---|
| Edge | sin1, terdekat |
20 ms |
| Node.js, region bawaan | iad1 |
230 ms |
| Node.js, region diganti | sin1 |
20 ms |
Region function Node.js diganti di pengaturan proyek, di vercel.json ("regions": ["sin1"]), atau per route dengan export const preferredRegion = "sin1". Pilih region yang dekat dengan database-nya: function di Edge yang jalan dekat user tapi menanyai database di Virginia tiga kali membayar 3 × 230 ms. Kerja yang banyak bicara dengan database lebih cepat kalau function-nya duduk di sebelah database.
Yang gak ada di Edge runtime
Edge runtime cuma membawa Web API: fetch, Request, Response, URL, Headers, TextEncoder, stream, dan crypto.subtle. Yang gak ada:
fsdanchild_process: gak bisa membaca file dari disk atau menjalankan program lain.- Modul native seperti
sharpataubcrypt, dan driver database yang butuh koneksi TCP biasa sepertipg. evaldannew Function: kode yang dibuat saat runtime ditolak.require: kode di Edge memakaiimport.
Route Edge yang meng-import fs gagal saat build, bukan diam-diam pindah ke Node.js. Ukuran kodenya juga dibatasi lebih kecil daripada function Node.js.
📌 Catatan versi Next.js
- Next.js 15 menghapus
request.geodanrequest.ipdariNextRequest. Kode lamarequest.geo?.countrysekarangundefined. Pakai headerx-vercel-ip-countryataugeolocation(request). - Next.js 15.5 membuat middleware bisa jalan di runtime Node.js (
export const config = { runtime: "nodejs" }). - Next.js 16 mengganti nama
middleware.tsjadiproxy.tsdan function-nya jadiproxy, yang jalan di runtime Node.js.middleware.tsmasih jalan tapi sudah deprecated; tetap pakai itu kalau butuh runtime Edge. Cek versi Next.js proyekmu sebelum menyalin contoh dari internet.
⚠️ Jebakan yang sering ketemu
- Matcher yang menangkap semuanya. Tanpa pengecualian
_nextdan file statis, middleware jalan untuk tiap file JavaScript, gambar, dan ikon: lebih lambat dan lebih mahal. - Cek negara sebelum cek login. Rewrite ke
/idkeluar duluan, dan pemeriksaan login untuk pengunjung Indonesia terlewat. - Query database dari Edge yang jauh dari database. Dekat dengan user gak ada gunanya kalau tiap query menyeberang 230 ms.
- Memakai
request.geodi Next.js 15 ke atas. Nilainya selalu kosong, jadi semua pengunjung dianggap dari Amerika.
TL;DR: Vercel Functions punya dua runtime: Node.js (lengkap, satu region, bawaan iad1) dan Edge (V8 isolate, jalan di region terdekat dengan pengunjung, tanpa fs, child_process, modul native, dan eval). export const runtime = "edge" men-deploy route ke edge network, bukan sebagai function Node.js. Middleware jalan sebelum halaman untuk tiap path yang cocok dengan matcher, dan menjawab dengan NextResponse.next(), redirect (307, alamat berubah), atau rewrite (alamat tetap, isi dari path lain); cek login sebelum cek negara. Edge cocok untuk auth, redirect, A/B testing, dan geolocation; query database, olah file, dan komputasi berat tempatnya di Node.js, di region dekat database. Di Next.js 15 request.geo hilang (pakai x-vercel-ip-country), dan di Next.js 16 middleware bernama proxy.ts.