Episode ini membedah routing Remix: pemetaan file route ke URL, nested routing dengan Outlet untuk layout sharing, dynamic routes dan catch-all routes, konvensi route lanjutan, serta navigasi dengan Link dan NavLink.

Di episode 3 kalian sudah punya project berjalan. Sekarang kita masuk ke salah satu pilar terkuat Remix: routing. Di framework lain, routing sering berupa daftar konfigurasi panjang. Di Remix, route adalah file — dan aturannya bisa dipelajari dalam beberapa menit.
Yang membedakan Remix dari kebanyakan framework adalah nested routes. URL /blog/halo-dunia tidak hanya menunjuk satu halaman, tetapi hierarki: layout blog mengapit halaman detail posting. Struktur ini membuat bagian UI yang tetap tidak pernah di-render ulang saat navigasi.
Episode 4 akan membawa kalian dari route paling sederhana sampai pola lanjutan: dynamic routes, catch-all, index routes, dan navigasi yang mulus lewat Link dan NavLink.
Setiap file di folder app/routes dipetakan langsung menjadi URL. Nama file menentukan jalurnya:
app/routes/_index.tsx -> / index route
app/routes/blog.tsx -> /blog
app/routes/contact.tsx -> /contactAturan ini konsisten dan bisa diprediksi. Setiap file route mengekspor komponen default yang di-render saat URL cocok. Tidak ada langkah konfigurasi tambahan di luar membuat file.
Satu file route berisi beberapa ekspor: komponen default untuk UI, loader dan action untuk data, meta untuk head, headers untuk respons, serta ErrorBoundary. Inilah yang disebut route module — satu file, satu URL, satu siklus hidup lengkap. Kalian sudah melihatnya sekilas di episode 2.
Nested routing bekerja lewat komponen Outlet. File route induk mengekspor layout dengan <Outlet />, dan route anak di-render di dalamnya. Contoh: semua halaman di bawah /blog memakai layout yang sama.
import { Outlet, Link } from "@remix-run/react";
export default function LayoutBlog() {
return (
<div>
<header>
<Link to="/blog">Daftar Blog</Link>
</header>
<main>
<Outlet />
</main>
</div>
);
}Komponen Outlet me-render route anak sesuai hierarki URL. Saat navigasi terjadi, hanya bagian route yang berubah yang me-render ulang; header dan main tetap dipertahankan.
Terkadang kalian ingin layout tanpa menambahkan segmen URL. Remix memakai garis bawah untuk ini: folder app/routes/blog._layout.tsx membuat layout untuk rute di bawah /blog tanpa mengubah URL. Pola underscore adalah cara Remix membedakan konvensi dari struktur URL aktual.
Untuk menangkap nilai dari URL, namai file dengan tanda dolar. File posts.$id.tsx mencocokkan /posts/apa-saja, dan nilainya tersedia lewat params di loader serta useParams di komponen.
import { useLoaderData, useParams } from "@remix-run/react";
export async function loader({ params }) {
return { id: params.id };
}
export default function DetailPost() {
const params = useParams();
const data = useLoaderData();
return <h1>Posting {params.id} -> data {data.id}</h1>;
}Loader menerima params dari segmen URL yang dimulai dolar. Untuk membuat path lebih dalam, kalian bisa memakai bentuk posts.$category.$slug.tsx untuk /posts/tekno/mengenal-remix.
File $.tsx mencocokkan semua URL di bawah levelnya — termasuk beberapa segmen sekaligus. Ini berguna untuk menangkap rute yang tidak dikenal atau membangun sistem file virtual. Nilai lengkapnya tersedia sebagai params["*"].
File bernama _index.tsx di dalam folder menjadi halaman default untuk segmen tersebut. Contoh: posts._index.tsx di-render saat URL /posts tanpa segmen tambahan, sedangkan posts.$id.tsx menangani /posts/123. Index route dipasangkan dengan route induknya, bukan dengan dirinya sendiri sebagai parent.
Route yang tidak mengekspor komponen default disebut resource route — respons penuh dikendalikan di kode. Contohnya endpoint JSON, file download, atau webhook. Ini cara Remix mengekspos API tanpa keluar dari konvensi filesystem, dan akan dipakai lagi di episode 13.
Gunakan Link dari @remix-run/react untuk navigasi antar halaman aplikasi. Link memakai alur internal Remix sehingga transisi lebih halus dan prefetch bisa diaktifkan. Jangan memakai tag a biasa untuk navigasi internal — gunakan a hanya untuk link eksternal.
import { NavLink } from "@remix-run/react";
export default function Nav() {
return (
<NavLink to="/blog" className={({ isActive }) =>
isActive ? "menu-aktif" : "menu-biasa"}>
Blog
</NavLink>
);
}NavLink otomatis menandai link yang sedang aktif lewat prop isActive — sempurna untuk menu navigasi. Untuk navigasi imperatif, ada useNavigate dan navigate(route) di dalam handler.
Ketika navigasi internal terjadi, Remix me-load loader route baru, lalu me-render dengan transisi. Karena tiap route punya loader sendiri, data yang dibutuhkan halaman berikutnya sudah tersedia sebelum halaman tersebut ditampilkan. Kombinasi nested route dan prefetch inilah yang membuat navigasi Remix terasa instan.
Episode 4 membuat kalian fasih membaca dan menulis route: file route menjadi URL, nested routing dengan Outlet, dynamic dan catch-all routes, konvensi index serta resource route, dan navigasi dengan Link serta NavLink. Struktur route yang baik sekarang ada di genggaman kalian.
Inti yang harus dibawa pulang:
_index.tsx adalah halaman default; $.tsx adalah catch-all.Di episode 5 selanjutnya kita akan membahas data loading dan actions — cara loader mengambil data di server, form submission dengan action, pengiriman JSON response, redirect, cookies, serta deferred data dan streaming. Routing dan data adalah dua sisi mata uang yang sama di Remix.