Revalidasi: ISR & On-Demand
Update konten statis tanpa rebuild: time-based dan on-demand revalidation.
ISR: statis yang bisa disegarkan
Bayangkan papan pengumuman di sekolah. Ada dua cara mengurusnya: (1) diganti rutin tiap jam sesuai jadwal, atau (2) diganti segera begitu ada pengumuman baru dari guru. Keduanya membuat papan tetap akurat tanpa harus membangun ulang seluruh papan setiap menit.
Itulah kenapa revalidasi ada. Kamu dihadapkan pada dilema klasik: halaman statis itu super cepat (disajikan langsung dari cache) tapi bisa basi, sedangkan halaman dinamis selalu segar tapi lambat (render + fetch tiap request). ISR (Incremental Static Regeneration) adalah jalan tengahnya: sajikan versi statis yang cepat, lalu regenerate di background saat waktunya tiba atau saat ada pemicu.
Time-based revalidation: regenerate terjadwal
// app/blog/page.tsx
// Contoh 1: artikel regenerate maksimal tiap 1 jam
export const revalidate = 3600; // dalam detik
export default async function Blog() {
const res = await fetch("https://api.example.com/posts");
const posts = await res.json();
return <PostList posts={posts} />;
}Alurnya perlu dipahami baik-baik karena tidak intuitif: pengunjung pertama yang datang SETELAH 1 jam berlalu masih menerima versi lama (cepat!), tapi kunjungannya memicu regenerate di background. Pengunjung berikutnya barulah mendapat versi baru. Pola ini disebut stale-while-revalidate: layani yang basi dulu, segarkan diam-diam.
Cara ini ideal untuk konten yang berubah terjadwal atau tidak kritis: blog, dokumentasi, halaman arsip.
On-demand revalidation: regenerate saat ada event
Kadang kamu tidak mau menunggu jadwal. Misalnya editor menekan "Publish" di CMS, artikel baru harus langsung tampil. Untuk itu ada revalidasi on-demand lewat Route Handler:
// app/api/revalidate/route.ts
// Contoh 2: endpoint yang dipanggil CMS setiap ada artikel baru
import { revalidatePath, revalidateTag } from "next/cache";
import { NextRequest } from "next/server";
export async function POST(req: NextRequest) {
// Lindungi endpoint: hanya CMS yang tahu secret ini boleh memicu
const secret = req.nextUrl.searchParams.get("secret");
if (secret !== process.env.REVALIDATE_SECRET) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}
revalidatePath("/blog"); // regenerate halaman /blog
return Response.json({ revalidated: true });
}Untuk kontrol yang lebih granular, pakai tags. Tandai fetch dengan tag, lalu revalidasi per tag tanpa menyentuh halaman lain:
// lib/api.ts
const res = await fetch("https://api.example.com/posts", {
next: { tags: ["posts"] },
});
// di tempat lain: revalidateTag("posts") meregenerasi semua
// halaman yang fetch-nya bertag "posts", halaman lain tidak tersentuh.Pola nyatanya: CMS punya webhook "on publish" yang memanggil /api/revalidate?secret=..., dan dalam hitungan detik artikel baru tampil tanpa rebuild atau redeploy.
Catatan teknis: Pilih time-based untuk konten yang "cukup segar berkala" (blog, docs), dan on-demand untuk konten yang "harus segar saat event" (publish CMS, update produk). Keduanya bisa digabung:
revalidate = 3600sebagai jaring pengaman, plus on-demand untuk momen penting. Dan jangan lupa: endpoint revalidasi WAJIB dilindungi secret, kalau tidak siapa pun bisa memaksa servermu regenerate terus-menerus.
Tantangan
Revalidasi manual
Buat halaman dengan revalidate = 60 yang menampilkan timestamp build. Buat juga API route yang memanggil revalidatePath. Panggil API-nya dan amati timestamp berubah.