Cache Components di Next.js 16 Tahun 2026: Panduan Lengkap use cache, PPR, dan Pertanyaan Interview
Panduan mendalam tentang Cache Components di Next.js 16: directive use cache di tiga cakupan, Partial Pre-Rendering, cacheLife profiles, cacheTag, keamanan cache, dan pertanyaan interview untuk developer senior tahun 2026.

Cache Components Next.js 16 merupakan perubahan terbesar dalam cara Next.js menangani caching sejak diperkenalkannya App Router. Model lama menyimpan semua data dalam cache secara default dan memerlukan pengecualian. Model baru tidak menyimpan apa pun dalam cache secara default dan memerlukan pengaktifan dengan direktif "use cache".
Next.js 16 berpindah dari caching implisit (semua di-cache, keluar dengan API dinamis) ke caching eksplisit (tidak ada yang di-cache, masuk dengan "use cache"). Perubahan tunggal ini memengaruhi routing, pengambilan data, rendering, dan cara pertanyaan interview dirumuskan.
Mengapa Next.js 16 Menggantikan Caching Implisit
Pendekatan caching implisit pada Next.js 15 menciptakan masalah yang semakin kompleks seiring pertumbuhan aplikasi. Developer sering mengalami kebocoran data yang tidak terduga ketika cache dibagikan antar pengguna yang berbeda. Debugging menjadi sulit karena tidak ada cara eksplisit untuk mengetahui komponen mana yang menggunakan cache dan mana yang tidak.
Perilaku default yang meng-cache semuanya juga menyebabkan konten kedaluwarsa yang tidak disengaja. Halaman yang seharusnya selalu menampilkan data terbaru malah menampilkan versi lama karena developer lupa menambahkan export const dynamic = 'force-dynamic'.
Dengan model eksplisit di Next.js 16, setiap keputusan caching menjadi terlihat dalam kode. Tidak ada lagi asumsi tersembunyi. Jika sebuah fungsi atau komponen di-cache, developer secara sadar menambahkan direktif "use cache". Pendekatan ini meningkatkan keamanan, prediktabilitas, dan kemudahan debugging.
Cara Kerja Direktif use cache pada Tiga Cakupan
Direktif "use cache" di Next.js dapat diterapkan pada tiga tingkat berbeda: tingkat file, tingkat komponen, dan tingkat fungsi. Setiap cakupan memberikan kontrol granular atas perilaku caching.
Caching Tingkat File
Menempatkan "use cache" di bagian atas file menjadikan seluruh halaman sebagai shell statis. Pendekatan ini ideal untuk halaman yang jarang berubah seperti halaman pricing atau about.
"use cache"
import { getPricingPlans } from "@/lib/data"
// Entire page is cached as a static shell
export default async function PricingPage() {
const plans = await getPricingPlans()
return (
<section>
{plans.map((plan) => (
<PricingCard key={plan.id} plan={plan} />
))}
</section>
)
}Seluruh halaman pricing di-cache sebagai satu unit. Setiap request akan menerima versi yang sama hingga cache di-invalidasi.
Caching Tingkat Komponen
Untuk kontrol yang lebih halus, direktif dapat ditempatkan di dalam komponen individual. Ini memungkinkan caching selektif pada bagian tertentu dari halaman.
async function ProductRecommendations({ categoryId }: { categoryId: string }) {
"use cache"
// categoryId becomes part of the automatic cache key
const products = await getTopProducts(categoryId)
return (
<ul>
{products.map((p) => (
<li key={p.id}>{p.name} - {p.price}</li>
))}
</ul>
)
}Parameter categoryId secara otomatis menjadi bagian dari cache key. Kategori berbeda akan memiliki cache entry terpisah.
Caching Tingkat Fungsi
Caching tingkat fungsi sangat berguna untuk operasi pengambilan data yang digunakan di banyak tempat dalam aplikasi.
import { cacheLife } from "next/cache"
export async function getArticleBySlug(slug: string) {
"use cache"
cacheLife("hours")
// slug is automatically included in the cache key
const article = await db.article.findUnique({ where: { slug } })
return article
}Fungsi ini dapat dipanggil dari berbagai komponen, dan hasilnya akan dibagikan dari cache yang sama berdasarkan parameter slug.
Partial Pre-Rendering: Shell Statis dengan Lubang Dinamis
Partial Pre-Rendering (PPR) adalah fitur cache components Next.js yang memungkinkan pengiriman shell statis secara instan sambil melakukan streaming konten dinamis. Konsep ini menggabungkan keuntungan static site generation dengan fleksibilitas server-side rendering.
import { Suspense } from "react"
import { UserGreeting } from "@/components/UserGreeting"
import { StaticSidebar } from "@/components/StaticSidebar"
import { RecentActivity } from "@/components/RecentActivity"
export default function DashboardPage() {
return (
<div className="grid grid-cols-12 gap-6">
{/* Cached static shell - served instantly */}
<StaticSidebar />
<main className="col-span-9">
{/* Dynamic - streams in after static shell */}
<Suspense fallback={<GreetingSkeleton />}>
<UserGreeting />
</Suspense>
{/* Dynamic - streams independently */}
<Suspense fallback={<ActivitySkeleton />}>
<RecentActivity />
</Suspense>
</main>
</div>
)
}Browser menerima StaticSidebar secara langsung dari cache edge. Sementara itu, UserGreeting dan RecentActivity di-stream secara independen saat data pengguna tersedia. Setiap komponen dinamis dibungkus dalam Suspense untuk menentukan batas streaming.
PPR mengurangi Time to First Byte (TTFB) secara signifikan karena shell statis dapat dilayani dari CDN. Pengguna melihat layout dan navigasi langsung, sementara konten personalisasi di-stream dalam hitungan milidetik berikutnya.
cacheLife Profiles: Menggantikan revalidate
Konfigurasi revalidate di Next.js 15 hanya mendukung satu angka tunggal. Next.js 16 memperkenalkan cacheLife dengan profil yang lebih ekspresif: "seconds", "minutes", "hours", "days", "weeks", atau profil kustom.
import { cacheLife } from "next/cache"
export async function getExchangeRates() {
"use cache"
cacheLife("minutes") // Revalidates every few minutes
const rates = await fetch("https://api.exchangerate.host/latest")
return rates.json()
}
export async function getCompanyInfo() {
"use cache"
cacheLife("weeks") // Rarely changes
return db.company.findFirst()
}Nilai tukar mata uang memerlukan pembaruan yang sering, sementara informasi perusahaan jarang berubah. Profil cacheLife membuat maksud developer menjadi jelas dalam kode.
Konfigurasi Profil Kustom
Untuk kebutuhan caching yang spesifik, profil kustom dapat didefinisikan dalam next.config.ts.
import type { NextConfig } from "next"
const config: NextConfig = {
cacheComponents: true,
cacheLife: {
// Custom profile for product data
product: {
stale: 300, // Serve stale for 5 minutes
revalidate: 3600, // Revalidate in background every hour
expire: 86400, // Hard expire after 24 hours
},
},
}
export default configProfil kustom product menentukan tiga fase: melayani versi stale selama 5 menit, memvalidasi ulang di background setiap jam, dan menghapus cache sepenuhnya setelah 24 jam.
Siap menguasai wawancara React / Next.js Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
cacheLife Kondisional
Durasi cache dapat disesuaikan secara dinamis berdasarkan hasil query.
export async function getProduct(id: string) {
"use cache"
const product = await db.product.findUnique({ where: { id } })
if (!product) {
// Short cache for missing items (may appear soon)
cacheLife("minutes")
return null
}
// Longer cache for existing products
cacheLife("product")
return product
}Produk yang tidak ditemukan di-cache singkat karena mungkin akan ditambahkan segera. Produk yang ada menggunakan profil product yang lebih lama.
cacheTag untuk Invalidasi Tertarget
Tag cache memungkinkan pengelompokan entry cache terkait dan menginvalidasinya secara bersamaan. Fitur ini sangat penting untuk menjaga konsistensi data.
import { cacheLife, cacheTag } from "next/cache"
export async function getProductById(id: string) {
"use cache"
cacheTag(`product-${id}`, "products")
cacheLife("days")
return db.product.findUnique({ where: { id } })
}Setiap produk ditandai dengan tag spesifik (product-123) dan tag umum (products). Ini memungkinkan invalidasi granular atau batch.
Invalidasi dengan revalidateTag
Server Actions menggunakan revalidateTag untuk menginvalidasi cache saat data berubah.
"use server"
import { revalidateTag } from "next/cache"
export async function updateProduct(id: string, data: ProductUpdate) {
await db.product.update({ where: { id }, data })
// Invalidate this specific product AND the product list
revalidateTag(`product-${id}`)
revalidateTag("products")
}Setelah update produk, cache untuk produk spesifik dan daftar produk keduanya di-invalidasi. Halaman yang menampilkan produk tersebut atau daftar produk akan mengambil data terbaru pada request berikutnya.
Hindari menggunakan terlalu banyak tag generik seperti "all" atau "global". Invalidasi tag yang luas dapat menyebabkan cache stampede ketika banyak entry di-refresh secara bersamaan.
Keamanan: use cache vs use cache private
Memahami perbedaan antara cache yang dibagikan dan cache privat sangat penting untuk keamanan aplikasi. Kesalahan dalam memilih direktif dapat menyebabkan kebocoran data pengguna.
// WRONG: User data in shared cache - data leak risk
export async function getUserDashboard(userId: string) {
"use cache"
return db.user.findUnique({
where: { id: userId },
include: { orders: true, preferences: true },
})
}
// CORRECT: Private cache scoped to the current user
export async function getUserDashboard() {
"use cache: private"
cacheLife("minutes")
const session = await cookies()
const userId = session.get("userId")?.value
return db.user.findUnique({
where: { id: userId },
include: { orders: true, preferences: true },
})
}Versi pertama berbahaya karena cache dibagikan antar pengguna. Jika pengguna A mengakses dashboard dengan userId tertentu, pengguna B mungkin menerima data yang sama dari cache.
Versi kedua menggunakan "use cache: private" yang membatasi cache ke sesi pengguna saat ini. Fungsi ini juga membaca userId dari cookies alih-alih menerimanya sebagai parameter, memastikan hanya pengguna yang terautentikasi yang dapat mengakses datanya sendiri.
| Direktif | Cakupan | Gunakan Ketika |
|-----------|-------|----------|
| "use cache" | Dibagikan, semua pengguna | Data publik: pricing, artikel, katalog produk |
| "use cache: private" | Per sesi pengguna | Data personalisasi: dashboard, pengaturan, riwayat pesanan |
| "use cache: remote" | Dibagikan, penyimpanan eksternal | Data high-traffic di lingkungan serverless |
Migrasi dari Next.js 15 ke Cache Components
Migrasi ke model caching eksplisit memerlukan audit sistematis terhadap basis kode yang ada. Langkah pertama adalah mengidentifikasi semua halaman dan komponen yang sebelumnya mengandalkan caching implisit.
Cari penggunaan fetch() tanpa opsi cache eksplisit. Di Next.js 15, fetch request di-cache secara default. Di Next.js 16, mereka tidak di-cache kecuali direktif "use cache" ditambahkan.
Perhatikan juga halaman yang menggunakan export const revalidate = N. Ini perlu dikonversi ke cacheLife() yang sesuai di dalam fungsi dengan direktif "use cache".
Untuk halaman yang sebelumnya menggunakan export const dynamic = 'force-dynamic', tidak ada perubahan yang diperlukan. Mereka sudah dinamis dan akan tetap dinamis di Next.js 16 karena tidak ada yang di-cache secara default.
Mulai dengan menambahkan "use cache" pada halaman statis yang jelas seperti landing pages dan dokumentasi. Kemudian, tambahkan caching granular pada komponen individual untuk halaman dengan konten campuran.
Pertanyaan Interview Next.js 16 tentang Cache Components
Pemahaman mendalam tentang partial pre-rendering dan cache components sering diuji dalam interview Next.js di tahun 2026. Berikut adalah pertanyaan umum beserta jawaban yang diharapkan.
P1: Apa perbedaan utama antara model caching Next.js 15 dan Next.js 16?
Next.js 15 menggunakan caching implisit dimana semua fetch request dan halaman di-cache secara default. Developer harus secara eksplisit mengecualikan dengan dynamic = 'force-dynamic' atau cache: 'no-store'. Next.js 16 membalikkan ini menjadi caching eksplisit dimana tidak ada yang di-cache kecuali direktif "use cache" ditambahkan. Perubahan ini meningkatkan keamanan dengan menghilangkan kebocoran data tidak disengaja dan membuat perilaku caching terlihat dalam kode.
P2: Bagaimana Partial Pre-Rendering bekerja dan apa keuntungannya?
PPR memungkinkan pengiriman shell statis secara instan sambil melakukan streaming konten dinamis. Shell statis yang dibungkus dengan "use cache" dilayani dari CDN edge, sementara komponen dinamis dalam Suspense boundaries di-stream saat data tersedia. Keuntungannya meliputi TTFB yang lebih rendah, pengalaman pengguna yang lebih baik dengan layout instan, dan fleksibilitas untuk mencampur konten statis dan dinamis dalam satu halaman.
P3: Kapan menggunakan "use cache" vs "use cache: private"?
Gunakan "use cache" untuk data publik yang sama untuk semua pengguna: halaman pricing, artikel blog, katalog produk. Gunakan "use cache: private" untuk data yang berbeda per pengguna: dashboard personalisasi, pengaturan akun, riwayat pesanan. Memilih yang salah dapat menyebabkan kebocoran data jika cache yang seharusnya privat dibagikan antar pengguna.
P4: Jelaskan cara kerja cacheTag dan revalidateTag.
cacheTag() menandai entry cache dengan satu atau lebih tag string. revalidateTag() menginvalidasi semua entry dengan tag tertentu. Contoh: produk dapat ditandai dengan product-123 dan products. Saat produk diperbarui, memanggil revalidateTag('product-123') menginvalidasi entry spesifik tersebut, sementara revalidateTag('products') menginvalidasi semua daftar produk. Ini memungkinkan invalidasi granular dan batch.
P5: Apa saja fase dalam profil cacheLife kustom?
Profil kustom memiliki tiga properti: stale menentukan berapa lama menyajikan versi stale sebelum memvalidasi ulang, revalidate menentukan interval untuk background revalidation, dan expire menentukan waktu kedaluwarsa keras ketika cache dihapus sepenuhnya. Contoh: stale: 300, revalidate: 3600, expire: 86400 berarti menyajikan stale 5 menit, memvalidasi ulang setiap jam, hapus setelah 24 jam.
P6: Bagaimana menangani komponen yang perlu data pengguna dalam halaman dengan PPR?
Bungkus komponen yang memerlukan data pengguna dalam Suspense boundary dengan fallback skeleton. Komponen tersebut tidak boleh menggunakan "use cache" jika datanya unik per pengguna, atau menggunakan "use cache: private" jika caching per sesi diinginkan. Shell halaman menggunakan "use cache" untuk dilayani instan, sementara komponen personalisasi di-stream setelahnya.
Untuk persiapan lebih lanjut, pelajari juga pertanyaan interview Next.js data fetching dan modul Next.js Server Actions.
Checklist Praktis untuk Implementasi Cache Components
- Aktifkan
cacheComponents: truedinext.config.tsdan hapus flagexperimental.ppratauexperimental.dynamicIO - Audit setiap halaman: tambahkan
"use cache"pada halaman statis dan fungsi pengambilan data untuk konten publik - Bungkus semua konten dinamis (spesifik pengguna, request-time) dalam
<Suspense>boundaries dengan skeleton fallback yang bermakna - Gunakan
"use cache: private"untuk fungsi yang mengakses cookies, headers, atau mengembalikan data personalisasi - Definisikan profil
cacheLifekustom untuk kategori data umum (data produk, sesi pengguna, konten statis) - Tambahkan
cacheTag()ke setiap fungsi cache yang mungkin memerlukan invalidasi sesuai permintaan - Uji dalam mode produksi dengan
next build && next startkarena perilaku caching dinext devberbeda secara signifikan - Pantau rasio cache-hit per halaman selama 24 jam sebelum meluncurkan ke halaman berikutnya
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Kesimpulan
- Next.js 16 menggantikan caching implisit dengan
"use cache"eksplisit pada tingkat file, komponen, dan fungsi - PPR kini stabil dan default di bawah
cacheComponents: true, menghadirkan shell statis dengan konten dinamis yang di-stream - Profil
cacheLifemenggantikanrevalidatedengan kontrol durasi cache tiga dimensi yang terpusat cacheTag+revalidateTagmemungkinkan invalidasi sesuai permintaan; tag yang hilang berarti hanya kedaluwarsa berdasarkan waktu"use cache: private"wajib digunakan untuk data spesifik pengguna guna mencegah kebocoran data antar pengguna- Pertanyaan interview di tahun 2026 berfokus pada pergeseran implisit-ke-eksplisit, alur rendering PPR, keamanan cache, dan perangkap migrasi dari Next.js 15
Tag
Bagikan
Artikel terkait

React Compiler di Tahun 2026: Memoization Otomatis dan Pertanyaan Interview
Pelajari React Compiler untuk memoization otomatis, pipeline kompilasi, aturan React, dan pertanyaan interview yang sering muncul di tahun 2026.

React 19 useEffectEvent dan Activity: API Baru dan Pertanyaan Interview 2026
Pembahasan mendalam useEffectEvent dan komponen Activity di React 19.2. Solusi stale closure, pre-rendering di background, contoh kode, dan pertanyaan interview teknis.

React 19: Server Components di Produksi - Panduan Lengkap
Kuasai React 19 Server Components di lingkungan produksi. Arsitektur, pola desain, streaming, caching, dan optimasi untuk aplikasi berkinerja tinggi.