Konvensi File App Router
Arti file-file spesial: page, layout, loading, error, not-found.
Analogi: papan nama jabatan
Di sebuah organisasi, orang yang memakai papan nama "Ketua" otomatis diperlakukan sebagai ketua: boleh memimpin rapat, suaranya didengar. Bukan karena orangnya istimewa, tapi karena labelnya memberi wewenang.
Di Next.js berlaku hal yang sama untuk file. File yang bernama page.tsx otomatis menjadi halaman. File bernama layout.tsx otomatis menjadi pembungkus. Nama file adalah "papan nama jabatan": Next.js membaca labelnya, lalu memberi perlakuan khusus tanpa perlu kamu daftarkan ke mana pun. Inilah yang disebut konvensi file, dan menghafalnya akan menghemat banyak waktu debugging.
File spesial dan jabatannya
| File | Fungsi |
|---|---|
page.tsx | UI unik sebuah route. Wajib ada agar route bisa diakses publik |
layout.tsx | UI bersama yang membungkus halaman-halaman di foldernya |
loading.tsx | Tampilan loading otomatis saat konten sedang disiapkan |
error.tsx | Tampilan error otomatis saat sesuatu gagal di segmen itu |
not-found.tsx | UI halaman 404 |
route.ts | API endpoint (mengembalikan data, bukan halaman) |
Tiga yang terakhir (loading, error, not-found) masing-masing punya modul tersendiri nanti di track ini. Untuk sekarang, fokus ke dua yang paling fundamental: page dan layout.
Kenapa sistem ini ada?
Alternatifnya adalah sistem pendaftaran manual seperti react-router: setiap halaman didaftarkan satu per satu di file config. Masalahnya, daftar itu bisa basi: halaman dihapus tapi pendaftarannya lupa dihapus (route hantu), atau halaman dibuat tapi lupa didaftarkan (404 misterius). Dengan konvensi file, kebenaran hanya ada di satu tempat: struktur file itu sendiri. Yang kamu lihat di folder adalah yang kamu dapat di browser. Tidak ada sumber kebenaran kedua yang bisa bertentangan.
Contoh 1: page.tsx menghidupkan sebuah route
Buat folder tentang berisi satu file ini, dan route /tentang langsung bisa diakses:
// app/tentang/page.tsx
export default function Tentang() {
return (
<main>
<h1>Tentang Kami</h1>
<p>Warung kopi kecil dengan mimpi yang besar.</p>
</main>
);
}Tanpa file ini, folder tentang/ hanyalah folder biasa yang tidak bisa dibuka lewat browser. page.tsx adalah satu-satunya file yang membuat route "hidup" dan bisa diakses publik. Ingat baik-baik: folder menentukan alamat, tapi page.tsx yang menentukan apakah alamat itu berpenghuni.
Strukturnya terlihat seperti ini:
app/
├── layout.tsx # membungkus SEMUA halaman
├── page.tsx # halaman /
└── tentang/
└── page.tsx # halaman /tentang
Contoh 2: layout.tsx membungkus halaman di foldernya
Sekarang tambahkan layout khusus untuk area tentang, misalnya sebuah sub-navigasi:
// app/tentang/layout.tsx
export default function TentangLayout({ children }: { children: React.ReactNode }) {
return (
<section>
<h2>Area Tentang</h2>
<nav>
<a href="/tentang">Profil</a> | <a href="/tentang/tim">Tim Kami</a>
</nav>
{children}
</section>
);
}Layout ini hanya membungkus halaman-halaman di dalam folder tentang/, tidak menyentuh halaman lain. Jika nanti kamu menambah app/tentang/tim/page.tsx, ia otomatis ikut terbungkus layout ini tanpa perlu didaftarkan. Pola bertahapnya jelas: Contoh 1 membuat route hidup, Contoh 2 menambah bingkai bersama di sekitarnya. Dan karena layout tidak di-render ulang saat berpindah antar halaman anaknya, navigasi terasa mulus (detailnya di modul routing nested).
Satu aturan universal untuk semua file spesial: komponennya harus memakai default export. Next.js mencari export default untuk mengetahui komponen mana yang harus dipakai.
Kesalahan umum pemula
1. Salah kapitalisasi nama file
SALAH: Menamai file Page.tsx (P kapital) atau pages.tsx, lalu heran kenapa route-nya 404 padahal file-nya jelas ada. Di sistem yang case-sensitive, Page.tsx dan page.tsx adalah dua file berbeda, dan Next.js hanya mengenali yang huruf kecil semua.
BENAR: Selalu huruf kecil persis: page.tsx, layout.tsx, loading.tsx. Copy-paste nama dari dokumentasi kalau ragu.
2. Folder ada tapi tidak punya page.tsx
SALAH: Membuat folder app/promo/ berisi banner.png dan layout.tsx, lalu bingung kenapa /promo menampilkan 404. Folder tanpa page.tsx tidak bisa diakses publik, titik.
BENAR: Tambahkan app/promo/page.tsx walau isinya sederhana. Tidak ada page.tsx berarti tidak ada route, sesederhana itu.
3. Mengisi route.ts dengan komponen React
SALAH: Membuat app/api/waktu/route.ts lalu menulis komponen <h1> di dalamnya, berharap menjadi halaman. Hasilnya error karena route.ts bukan untuk UI.
BENAR: route.ts adalah API endpoint: ia mengekspor fungsi seperti GET yang mengembalikan Response (biasanya JSON), bukan JSX. Untuk halaman, selalu pakai page.tsx. Keduanya punya modul tersendiri: halaman di modul routing, API di modul Route Handlers.
4. Lupa default export
SALAH: export function Tentang() tanpa kata default. File-nya benar, lokasinya benar, namanya benar, tapi halamannya blank atau error karena Next.js tidak menemukan komponen yang harus di-render.
BENAR: export default function Tentang(). Jadikan ini refleks: setiap file spesial Next.js memakai default export.
Tantangan
Tebak route
Diberi struktur: app/blog/[slug]/page.tsx dan app/blog/layout.tsx. Tulis URL yang bisa diakses dan file mana yang membungkus mana.