Di Next.js App Router, routing, rendering, dan pengambilan data saling terhubung lewat struktur folder. Satu file page tidak hanya mewakili halaman, tapi juga bagian dari alur render yang bisa dijalankan di server, di browser, atau kombinasi keduanya.
Topik inti di halaman ini:
App Router: sistem routing berbasis folder di direktori app/
Server Component: komponen default yang dirender di server
Client Component: komponen dengan interaksi browser seperti state dan event handler
Data fetching: cara mengambil data di server, client, atau lewat route handler
Kenapa penting
Kalau pola ini tidak dipahami, proyek Next.js cepat jadi campur aduk:
semua komponen dipindah ke client padahal tidak perlu
data diambil di tempat yang salah
halaman terasa lambat karena bundle membesar
interaksi UI malah rusak karena server component dipaksa menangani state browser
Di Next.js, keputusan soal server/client bukan detail kecil. Keputusan itu memengaruhi:
kapan HTML bisa tampil
apa yang masuk ke JavaScript bundle
bagaimana data dirender ulang
apakah UI bisa interaktif di browser
seberapa mudah halaman di-cache atau di-stream
Cara kerja App Router
App Router memakai struktur folder untuk membentuk route. Contoh sederhana:
layout.tsx = kerangka yang membungkus route turunan
loading.tsx = UI saat route sedang diproses
error.tsx = fallback saat render gagal
not-found.tsx = tampilan 404 pada segment tertentu
Cara bacanya sederhana:
app/page.tsx → route /
app/dashboard/page.tsx → route /dashboard
app/products/[id]/page.tsx → route dinamis seperti /products/123
Layout bersifat bertingkat. Root layout membungkus semua route, lalu sub-layout membungkus segment di bawahnya. Karena itu App Router cocok untuk UI yang punya area tetap, misalnya navbar, sidebar, atau shell dashboard.
Server Component dan Client Component
Secara default, file di App Router adalah Server Component. Kalau ingin komponen berjalan di browser, file itu harus diberi directive:
tsx
'use client'
Server Component
Server Component dipakai untuk bagian yang tidak butuh interaksi browser langsung.
Ciri umum:
dirender di server
bisa akses data source langsung dari server
tidak membawa hook browser seperti useState dan useEffect
bundle ke client lebih kecil karena logika tetap di server
Cocok untuk:
halaman yang dominan membaca data
layout dan shell aplikasi
konten statis atau semi-statis
komponen presentasional yang tidak butuh event handler browser
Client Component
Client Component dipakai ketika UI butuh interaksi browser.
Ciri umum:
dirender ulang di browser setelah hidrasi
bisa memakai useState, useEffect, useRef, event handler, dan hook browser lain
ikut masuk ke JavaScript bundle client
Cocok untuk:
form interaktif
dropdown, modal, tab, carousel
pencarian live
state UI lokal
komponen yang bergantung pada API browser atau event DOM
Aturan praktis
Pakai server component sebagai default. Naikkan ke client component hanya untuk bagian yang benar-benar butuh interaksi.
Itu berarti pola yang sehat biasanya begini:
halaman dan data utama tetap di server
komponen kecil yang interaktif dipisah jadi client component
server component boleh membungkus client component
client component tidak perlu menelan seluruh halaman
Kalau terlalu banyak area dijadikan client component, efeknya biasanya langsung terasa di bundle size dan waktu hidrasi.
Data fetching
Di App Router, data bisa diambil dengan beberapa pola. Yang paling penting bukan hanya “bisa ambil dari mana”, tapi “sebaiknya di mana”.
1. Fetch di Server Component
Ini pola yang paling umum untuk data halaman.
tsx
async function getPosts() { const res = await fetch('https://example.com/api/posts') return res.json()}export default async function Page() { const posts = await
Kelebihan pola ini:
data sudah tersedia saat render server
HTML awal bisa berisi konten nyata
cocok untuk SEO dan first paint
logika fetch tetap dekat dengan halaman yang memakai data
2. Fetch di Client Component
Pakai ini kalau data bergantung pada interaksi browser atau update setelah halaman tampil.
Biayanya adalah data tidak langsung ada pada HTML awal, jadi UI sering perlu loading state.
3. Fetch lewat Route Handler
Route handler dipakai kalau ingin membuat endpoint internal di dalam aplikasi Next.js.
Contoh lokasi:
text
app/api/posts/route.ts
Pola ini berguna untuk:
menyembunyikan akses ke sumber data tertentu
merapikan logika integrasi
memberi endpoint untuk client component
membuat API internal yang konsisten
4. Server Actions
Server Actions berguna untuk aksi yang mengubah data dari form atau interaksi UI, lalu diproses di server.
Meskipun bukan pengganti data fetching murni, server actions sering dipasangkan dengan fetch karena alurnya saling terkait: baca data di server, kirim perubahan ke server, lalu refresh atau revalidate hasilnya.
Alur request dan render
Secara praktis, urutannya biasanya seperti ini:
User membuka route.
Next.js mencocokkan URL dengan folder di app/.
Layout yang relevan dimuat.
Server Component dirender di server.
Data diambil selama render server jika dibutuhkan.
HTML awal dikirim ke browser.
Client Component di-hydrate agar interaktif.
Interaksi user berjalan di browser.
Loading diagram...
Diagram ini menunjukkan batas penting: server menyelesaikan render awal, lalu browser mengambil alih bagian yang interaktif.
Pembagian tanggung jawab server dan client
Cara paling aman membaginya adalah seperti ini:
Loading diagram...
Pembagian ini penting karena setiap sisi punya tugas berbeda:
Server: routing, data prep, render awal, integrasi backend
Client: interaksi, state lokal, event browser, update UI setelah halaman tampil
Implikasi untuk rendering
Pemilihan server atau client component punya efek langsung ke rendering.
Kalau memakai server component
HTML awal lebih kaya isi
loading awal biasanya lebih cepat untuk halaman berbasis data
JavaScript yang dikirim ke browser cenderung lebih sedikit
rendering ulang untuk data bisa lebih terkontrol
Kalau memakai client component
browser perlu menunggu hidrasi untuk interaksi penuh
bundle client membesar kalau terlalu banyak komponen dipindah ke browser
lebih cocok untuk UI yang hidup dan banyak event
data sering perlu loading state karena tidak muncul pada render server awal
Trade-off utama
Server component unggul untuk konten dan data awal
Client component unggul untuk interaksi dan state yang berubah di browser
Campuran keduanya biasanya hasil paling sehat
Contoh pola komposisi yang sehat
Satu halaman biasanya tidak sepenuhnya server atau client. Yang umum adalah komposisi seperti ini:
tsx
// app/dashboard/page.tsximport DashboardFilters from './dashboard-filters'export default async function Page() { const data = await getDashboardData() return ( <section> <h1>Dashboard</h1>
Lalu DashboardFilters bisa menjadi client component kalau butuh state dropdown atau input.
Pola ini menjaga:
data utama tetap dirender di server
interaksi hanya hidup di komponen yang butuh
bundle client tetap terkendali
Catatan implementasi
Jadikan server component sebagai default.
Naikkan ke client component hanya kalau butuh state, efek, atau event browser.
Taruh data fetching sedekat mungkin dengan pemakaian datanya.
Hindari memindahkan satu halaman penuh ke client hanya karena ada satu tombol interaktif.
Gunakan route handler saat butuh endpoint internal yang dipanggil client.
Gunakan server action untuk aksi perubahan data dari form atau interaksi server-side.
Kalau halaman terasa lambat, cek dulu apakah terlalu banyak komponen di client.
Kalau SEO dan konten awal penting, utamakan fetch di server.
Kalau data bergantung pada event user atau API browser, fetch di client lebih masuk akal.
Kesalahan umum
Menambahkan 'use client' di root komponen tanpa alasan jelas.
Mengambil semua data di useEffect padahal data itu dibutuhkan saat render awal.
Memakai client component untuk komponen yang sebenarnya statis.
Menaruh interaksi kompleks di server component, lalu bingung kenapa hook browser tidak bisa dipakai.
Mencampur server-only logic dan browser logic dalam satu file tanpa batas yang jelas.
Istilah
App Router: sistem routing Next.js berbasis folder di app/.
Layout: wrapper yang dipakai bersama oleh beberapa route.
Server Component: komponen yang dirender di server dan tidak membawa interaksi browser.
Client Component: komponen yang berjalan di browser dan bisa memakai state serta event handler.
Hydration: proses membuat UI yang sudah dirender server menjadi interaktif di browser.
Route Handler: endpoint API di dalam aplikasi Next.js.
Server Action: fungsi server yang dipanggil dari UI untuk aksi perubahan data.
Revalidation: proses memperbarui cache atau render ulang data setelah perubahan.
Referensi cepat
App Router dipakai untuk struktur route berbasis folder.
Server component dipakai untuk render awal dan data fetching server-side.
Client component dipakai untuk interaksi browser.
Data fetching paling aman dimulai dari kebutuhan render dan interaksi, bukan dari kebiasaan lama semata.