Nested Routing
Route bersarang: dashboard/settings dan pewarisan layout.
Analogi: gedung bertingkat
Bayangkan sebuah gedung tiga lantai. Lobi utama di lantai dasar dilewati semua orang, itu root layout. Lorong lantai dua hanya dilewati orang yang menuju lantai dua, itu layout dashboard. Kamar-kamar di lantai dua adalah halaman-halamannya.
Sekarang bayangkan kamu pindah dari kamar 201 ke kamar 202. Apakah gedungnya dirobohkan lalu dibangun ulang? Apakah lorong lantai duanya dibongkar? Tentu tidak. Yang berganti hanya isi kamar. Lorongnya tetap, lampunya tetap menyala, dan kalau kamu menaruh tas di lorong (state), tas itu tetap di sana saat kamu kembali.
Itulah cara kerja nested route dan layout di Next.js: pindah antar halaman anak tidak membangun ulang layout parent-nya.
Route bersarang: folder di dalam folder
Aturannya lanjutan dari modul sebelumnya: folder di dalam folder berarti URL bersarang.
app/
└── dashboard/
├── page.tsx → /dashboard
└── settings/page.tsx → /dashboard/settings
Setiap tingkat folder menambah satu segmen URL. Polanya sama persis, hanya lebih dalam. Tidak ada konsep baru di sini, hanya penerapan berulang dari "folder menentukan URL".
Pewarisan layout: bingkai yang menurun
Di sinilah hal menarik terjadi. Layout yang ditaruh di sebuah folder otomatis membungkus semua halaman di dalam folder itu (dan folder di bawahnya). Ini disebut pewarisan layout.
Contoh 1: layout dashboard dengan sidebar
// app/dashboard/layout.tsx
import Link from "next/link";
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div style={{ display: "flex", gap: "24px" }}>
<aside>
<h2>Menu Dashboard</h2>
<nav>
<Link href="/dashboard">Ringkasan</Link>
<br />
<Link href="/dashboard/settings">Pengaturan</Link>
</nav>
</aside>
<main>{children}</main>
</div>
);
}Layout ini hanya berlaku untuk /dashboard dan semua yang di bawahnya. Halaman /tentang tidak tersentuh. Perhatikan {children}: di sanalah halaman anak yang sedang dibuka akan disuntikkan. Lupa menulis {children} berarti halaman anak tidak pernah tampil, salah satu bug paling umum (lihat bagian kesalahan di bawah).
Contoh 2: halaman-halaman anaknya
// app/dashboard/page.tsx
export default function Dashboard() {
return <h1>Ringkasan penjualan hari ini</h1>;
}// app/dashboard/settings/page.tsx
export default function Settings() {
return <h1>Pengaturan toko</h1>;
}Buka /dashboard: kamu melihat sidebar + "Ringkasan penjualan hari ini". Klik "Pengaturan": URL berubah ke /dashboard/settings, konten kanan berganti menjadi "Pengaturan toko", tapi sidebar tidak berkedip, tidak loading ulang, tidak dibangun ulang. Itulah pewarisan layout beraksi.
Kenapa layout parent tidak di-render ulang? Masalah yang diselesaikan
Di website tradisional (atau SPA yang ceroboh), setiap pindah halaman berarti seluruh UI dibangun ulang dari nol: sidebar ikut hancur lalu dibuat lagi, menyebabkan kedipan dan state yang hilang (misalnya menu yang sedang terbuka tiba-tiba tertutup, atau scroll sidebar kembali ke atas).
Next.js menghindari ini dengan mempertahankan layout parent tetap ter-mount saat navigasi terjadi di antara anak-anaknya. Hanya segmen halaman yang berganti yang di-render ulang. Hasilnya tiga keuntungan sekaligus: tidak ada kedipan UI, state di layout (menu aktif, input pencarian di sidebar) tetap terjaga, dan navigasi terasa jauh lebih cepat karena lebih sedikit yang dikerjakan ulang.
Progresinya dari Contoh 1 ke Contoh 2 menunjukkan pola kerja nyatanya: definisikan bingkai bersama sekali di layout, lalu fokus menulis konten unik di setiap page. Tanpa pola ini, kamu akan meng-copy-paste sidebar ke setiap halaman, dan setiap perubahan sidebar berarti mengedit sepuluh file.
Catatan teknis: Perilaku "tidak re-render" ini juga berarti data fetching di layout tidak dijalankan ulang saat pindah antar anak. Kalau kamu butuh sesuatu yang selalu segar di setiap navigasi (misalnya jam atau banner promo acak), taruh di page, bukan di layout. Untuk kasus di mana kamu justru ingin layout me-reset state-nya, ada file khusus bernama template.tsx yang dibahas di modul template vs layout.
Kesalahan umum pemula
1. Copy-paste sidebar ke setiap halaman
SALAH: Menulis ulang JSX sidebar yang sama di dashboard/page.tsx, dashboard/settings/page.tsx, dan setiap halaman dashboard lain. Saat desain sidebar berubah, harus edit semua file satu per satu, dan pasti ada yang terlewat.
BENAR: Satu dashboard/layout.tsx seperti Contoh 1. Satu sumber kebenaran untuk UI bersama, perubahan cukup di satu tempat.
2. Lupa me-render {children} di layout
SALAH: Layout hanya me-return sidebar tanpa {children}. Hasilnya halaman anak tampil blank: sidebar ada, kontennya tidak. Membingungkan karena tidak ada pesan error yang jelas.
BENAR: Selalu sertakan {children} di posisi konten seharusnya tampil. Anggap {children} sebagai lubang di bingkai tempat foto dipasang: tanpa lubang, tidak ada foto yang terlihat.
3. Menaruh konten khusus satu halaman di layout
SALAH: Menulis judul "Pengaturan Toko" langsung di dashboard/layout.tsx karena "kebetulan lagi buka halaman pengaturan". Akibatnya judul itu muncul juga di halaman ringkasan dan semua halaman dashboard lain.
BENAR: Layout hanya untuk UI yang benar-benar bersama (sidebar, breadcrumb, header seksi). Konten unik milik masing-masing page.
4. Heran kenapa konten layout tidak update saat navigasi
SALAH: Menaruh jam digital atau data yang harus selalu segar di layout, lalu bingung kenapa angkanya tidak berubah saat pindah halaman anak.
BENAR: Pahami kontraknya: layout dipertahankan antar navigasi anak, jadi ia memang tidak di-render ulang. Butuh yang selalu segar? Taruh di page. Butuh layout yang me-reset setiap navigasi? Pelajari template.tsx di modul template vs layout.
Tantangan
Dashboard mini
Buat /dashboard dan /dashboard/settings dengan layout khusus berisi sidebar sederhana. Buktikan navigasi antar keduanya tidak me-reset state (mis. counter di layout).