Cara membuat slug route Next.js yang benar memakai folder dinamis app/blog/[slug]/page.tsx lalu membaca params.slug di Server Component. Kegagalan paling sering bukan di kodenya, melainkan nama folder salah tulis, params dibaca di Client Component tanpa await, atau slug tidak dinormalisasi sebelum dicocokkan ke database.
Langkah Membuat Slug Route [slug] di App Router
Dynamic route memakai kurung siku. Static route seperti /blog/tentang cocok untuk halaman tetap, dynamic route /blog/[slug] cocok untuk konten dari database, sedangkan search params ?q=next cocok untuk filter dan pencarian.
- Buat struktur app/blog/[slug]/page.tsx.
- Baca params sebagai Server Component async.
- Ambil data berdasarkan slug, bukan id mentah.
- Jalankan build untuk memastikan tidak ada bentrok route.
// app/blog/[slug]/page.tsx
export default async function BlogDetail({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params;
return <h1>Slug: {slug}</h1>;
}
- Gunakan kurung siku satu level untuk satu segmen.
- Gunakan params untuk path, searchParams untuk query.
- Jangan campur API Pages Router seperti getServerSideProps di sini.
Slug Tidak Ketemu Sering Karena 3 Hal Ini
Error 404 hampir selalu muncul setelah slug diklik dari daftar artikel.
- Folder tertulis [slugs], (slug), atau tanpa kurung sehingga Next.js menganggapnya static route.
- Params dibaca tanpa await di Next.js terbaru sehingga nilainya undefined.
- Slug berisi huruf besar, spasi, atau karakter %20 tetapi dicocokkan langsung ke database.
| Masalah | Penyebab | Solusi |
|---|---|---|
| 404 saat buka /blog/judul | Nama folder tidak persis [slug] | Samakan nama folder dan pemakaian params |
| params undefined | Lupa await params async | Ubah komponen jadi async lalu await params |
| Data tidak cocok | Slug belum dinormalisasi | Normalisasi sebelum query database |
Normalisasi Slug dan Validasi Not Found
Simpan slug dalam bentuk final saat artikel dibuat. Saat membaca, ubah input ke format sama sebelum query.
import { notFound } from "next/navigation";
function toSlug(text: string) {
return text.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
}
const slug = toSlug(rawSlug);
const post = await getPostBySlug(slug);
if (!post) notFound();
- Validasi tetap dilakukan di server sebelum query.
- Panggil notFound() untuk slug asing agar tampil halaman 404 bawaan.
- Hindari membuat slug berbeda hanya karena beda kapital atau spasi.
FAQ
Apakah slug route sama dengan dynamic route [id]?
Mekanismenya sama, bedanya [slug] memakai teks ramah URL sedangkan [id] biasanya memakai angka atau UUID.
Di mana membaca slug agar tetap Server Component?
Baca langsung dari argumen params di page.tsx tanpa use client dan tanpa hook navigasi client.
Bagaimana menangani slug dengan spasi dan karakter khusus?
Normalisasi saat simpan dan saat baca dengan fungsi toSlug yang sama agar hasilnya konsisten.