Salah satu kekuatan utama Next.js adalah fleksibilitas dalam mengambil data. Kamu bisa memilih kapan dan di mana data di-fetch — di server sebelum halaman dimuat, saat build time, atau langsung di browser. Artikel ini membahas empat pendekatan utama dan kapan harus menggunakannya.
Di React biasa, data fetching hampir selalu terjadi di browser menggunakan useEffect. Ini berarti pengguna melihat halaman kosong dulu, baru kemudian data muncul setelah JavaScript selesai berjalan.
Next.js memungkinkan data di-fetch di server, sehingga HTML yang diterima browser sudah berisi data lengkap. Hasilnya: halaman lebih cepat, SEO lebih baik, dan pengalaman pengguna yang lebih mulus.
SSR mengambil data setiap kali ada request. Setiap pengguna yang membuka halaman akan memicu fetch data baru di server, lalu HTML yang sudah berisi data dikirim ke browser.
// app/dashboard/page.tsx
async function DashboardPage() {
const data = await fetch('https://api.example.com/dashboard', {
cache: 'no-store' // Selalu fetch ulang, tidak pakai cache
}).then(r => r.json())
return <div>{data.username}</div>
}
// pages/dashboard.tsx
export async function getServerSideProps() {
const data = await fetch('https://api.example.com/dashboard').then(r => r.json())
return {
props: { data }
}
}
export default function Dashboard({ data }) {
return <div>{data.username}</div>
}
Kelebihan: Data selalu fresh
Kekurangan: Lebih lambat karena setiap request harus menunggu fetch selesai
Belum familiar dengan App Router dan Pages Router? Baca dulu App Router vs Pages Router: Mana yang Harus Kamu Pakai? sebelum melanjutkan artikel ini.
SSG mengambil data saat build time. HTML dibuat sekali ketika aplikasi di-build, lalu disimpan dan dikirim langsung ke pengguna tanpa fetch ulang.
// app/blog/page.tsx
async function BlogPage() {
const posts = await fetch('https://api.example.com/posts', {
cache: 'force-cache' // Cache permanen, hanya fetch saat build
}).then(r => r.json())
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
// pages/blog/index.tsx
export async function getStaticProps() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json())
return {
props: { posts }
}
}
export default function Blog({ posts }) {
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
Untuk halaman dengan URL dinamis (seperti /blog/[slug]), gunakan getStaticPaths di Pages Router:
// pages/blog/[slug].tsx
export async function getStaticPaths() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json())
return {
paths: posts.map(post => ({ params: { slug: post.slug } })),
fallback: false
}
}
export async function getStaticProps({ params }) {
const post = await fetch(`https://api.example.com/posts/${params.slug}`).then(r => r.json())
return {
props: { post }
}
}
Kelebihan: Sangat cepat, bisa di-cache di CDN
Kekurangan: Data bisa stale, perlu build ulang untuk update konten
ISR adalah solusi di antara SSR dan SSG. Halaman tetap di-generate secara statis, tapi bisa diperbarui secara otomatis setelah interval waktu tertentu tanpa harus build ulang seluruh aplikasi.
// app/products/page.tsx
async function ProductsPage() {
const products = await fetch('https://api.example.com/products', {
next: { revalidate: 3600 } // Revalidasi setiap 1 jam
}).then(r => r.json())
return (
<ul>
{products.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
)
}
// pages/products/index.tsx
export async function getStaticProps() {
const products = await fetch('https://api.example.com/products').then(r => r.json())
return {
props: { products },
revalidate: 3600 // Revalidasi setiap 1 jam
}
}
Kelebihan: Cepat seperti SSG, tapi konten bisa diperbarui
Kekurangan: Ada jeda waktu antara update data dan halaman yang ditampilkan
RSC bukan sekadar strategi data fetching — ini adalah perubahan arsitektur. Dengan RSC, komponen itu sendiri yang berjalan di server dan bisa langsung mengakses database atau API tanpa melewati endpoint tambahan.
// app/users/page.tsx
import { db } from '@/lib/database'
async function UsersPage() {
// Langsung query database — kode ini hanya berjalan di server
const users = await db.user.findMany({
select: { id: true, name: true, email: true }
})
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}
Tidak ada API endpoint, tidak ada useEffect, tidak ada loading state — data sudah ada saat HTML dikirim ke browser.
| SSR | RSC | |
|---|---|---|
| Kapan berjalan | Setiap request | Setiap request (tapi lebih efisien) |
| JavaScript ke browser | ✅ Dikirim (untuk hydration) | ❌ Tidak dikirim |
| Bisa akses DB langsung | ✅ Ya | ✅ Ya |
| Bisa pakai hooks | ✅ Ya | ❌ Tidak |
RSC tidak mengirimkan JavaScript komponen ke browser sama sekali, sehingga bundle size lebih kecil.
| SSR | SSG | ISR | RSC | |
|---|---|---|---|---|
| Data di-fetch | Tiap request | Saat build | Berkala | Tiap request |
| Kecepatan | ⚡⚡ | ⚡⚡⚡ | ⚡⚡⚡ | ⚡⚡ |
| Data freshness | ✅ Selalu fresh | ❌ Bisa stale | ⚠️ Tergantung interval | ✅ Selalu fresh |
| SEO friendly | ✅ | ✅ | ✅ | ✅ |
| Cocok untuk | Dashboard, profil | Blog, docs | Berita, produk | Semua halaman App Router |
Data berubah tiap detik dan berbeda per user?
└─ SSR
Konten statis, jarang berubah?
└─ SSG
Konten berubah tapi tidak harus real-time?
└─ ISR
Pakai App Router dan butuh akses DB langsung?
└─ RSC
Tidak ada satu strategi yang paling benar — semuanya punya tempat masing-masing:
Di satu aplikasi Next.js, kamu bisa menggunakan keempat strategi ini sekaligus — setiap halaman bisa punya pendekatan yang berbeda sesuai kebutuhannya.
SSR mengambil data setiap kali ada request — datanya selalu fresh tapi butuh waktu lebih lama. SSG mengambil data sekali saat build — halamannya sangat cepat tapi data bisa ketinggalan jika tidak di-rebuild.
Bisa. Di App Router, cukup tambahkan next: { revalidate: detik } pada opsi fetch. Tidak perlu menggunakan getStaticProps seperti di Pages Router.
Boleh, bahkan dianjurkan. Halaman blog bisa pakai SSG, halaman dashboard pakai SSR, halaman produk pakai ISR — semua bisa berjalan bersamaan dalam satu proyek Next.js.
Tidak. RSC dan SSR adalah konsep yang berbeda dan saling melengkapi. RSC fokus pada arsitektur komponen yang berjalan di server, sementara SSR adalah strategi rendering halaman. Di App Router, RSC adalah fondasi yang di atasnya SSR, SSG, dan ISR bisa diterapkan.
Karena useEffect berjalan di browser setelah halaman sudah dimuat, sehingga pengguna melihat halaman kosong terlebih dahulu. Ini buruk untuk SEO dan pengalaman pengguna. Next.js menyediakan cara fetch data di server agar HTML yang diterima browser sudah berisi data lengkap.
Masih relevan jika kamu menggunakan Pages Router. Namun jika menggunakan App Router, kedua fungsi ini tidak tersedia — data fetching dilakukan langsung di dalam komponen menggunakan async/await.