Layouts and nested routes
Blog pages share a header and a footer. To avoid repeating them in every file you use a layout — a route that renders the shared part and leaves a slot for the nested page. That slot is marked with the Outlet component.
The layout component
Create app/routes/layout.tsx:
// app/routes/layout.tsx
import { Outlet } from "react-router";
export default function Layout() {
return (
<>
<header>My blog</header>
<main>
<Outlet />
</main>
<footer>© 2026</footer>
</>
);
}The nested page whose address is currently open is rendered in place of Outlet.
Connecting the layout
layout(file, [routes]) wraps routes in a layout:
// app/routes.ts
import { type RouteConfig, index, layout, route } from "@react-router/dev/routes";
export default [
layout("routes/layout.tsx", [
index("routes/home.tsx"),
route("about", "routes/about.tsx"),
]),
] satisfies RouteConfig;Now both / and /about show the "My blog" header and the footer. layout itself adds nothing to the address.
A nested route with an address
If you pass an array as the third argument of route, the route becomes a parent: its address is the beginning of the children's addresses, and its component is their layout. An index route inside is the page for the parent's own address:
// app/routes.ts
route("dashboard", "routes/dashboard.tsx", [
index("routes/dashboard-home.tsx"), // /dashboard
route("stats", "routes/dashboard-stats.tsx"), // /dashboard/stats
]),app/routes/dashboard.tsx must also contain an Outlet, otherwise the child pages never appear.
Prefix only
When you need a shared address without a shared component, use prefix:
// app/routes.ts
import { prefix, route } from "@react-router/dev/routes";
// inside the routes array:
...prefix("admin", [
route("posts", "routes/admin-posts.tsx"), // /admin/posts
route("users", "routes/admin-users.tsx"), // /admin/users
]),prefix returns an array, so it is spread with the ... operator.
Summary
| Function | Address | Component |
|---|---|---|
route with children | Adds a segment | Layout with Outlet |
layout | Unchanged | Layout with Outlet |
prefix | Adds a segment | None |
index | The parent's address | A page |
Common mistake
Routes are placed inside layout, but the page shows only the header. The cause is almost always the same — the layout component is missing <Outlet />. The layout decides where the child page goes, and without Outlet it is simply not rendered.