
Next.js Routing
ā² Next.js Routing
The App Router maps folders to URLs. This cheatsheet covers dynamic segments, route groups, parallel routes, and intercepting routes.
ā Dynamic segments ā Catch-all segments ā Route groups ā Parallel routes ā Intercepting routes ā Linking and navigation
#nextjs #react #approuter #routing #webdev #frontend #coding #tips
Next.js uses the file system to define routes. Folders create URL segments, and special folder syntax enables advanced patterns.
| Convention | Example | Matches |
|---|---|---|
| Static segment | app/blog/ | /blog |
| Dynamic segment | app/blog/[slug]/ | /blog/hello |
| Catch-all | app/docs/[...slug]/ | /docs/a, /docs/a/b |
| Optional catch-all | app/shop/[[...slug]]/ | /shop, /shop/a, /shop/a/b |
| Route group | app/(marketing)/ | No URL segment added |
| Private folder | app/_components/ | Excluded from routing |
| Parallel route | app/@modal/ | Rendered alongside, not a URL |
| Intercepting | app/(.)photo/ | Intercepts a route from here |
Static segments
A plain folder name creates a static URL segment.
app
āāā page.tsx ā /
āāā blog
āāā page.tsx ā /blog// app/blog/page.tsx ā /blog
export default function BlogPage() {
return <h1>Blog</h1>;
}Dynamic segments
Use square brackets to create a dynamic segment.
app
āāā blog
āāā [slug]
āāā page.tsx ā /blog/hellohello will be passed to page.tsx as a param.
// app/blog/[slug]/page.tsx ā /blog/hello-world
export default async function Post({ params }) {
const { slug } = await params;
return <h1>{slug}</h1>;
}Generate static params at build time.
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map((post) => ({ slug: post.slug }));
}Catch-all segments
Match multiple segments with [...slug].
app
āāā docs
āāā [...slug]
āāā page.tsx ā /docs/a, /docs/a/b// app/docs/[...slug]/page.tsx
// /docs/a ā { slug: ["a"] }
// /docs/a/b ā { slug: ["a", "b"] }
export default async function Docs({ params }) {
const { slug } = await params;
}Optional catch-all segments
Use [[...slug]] to also match the parent path.
app
āāā shop
āāā [[...slug]]
āāā page.tsx ā /shop, /shop/a, /shop/a/b// app/shop/[[...slug]]/page.tsx
// /shop ā { slug: undefined }
// /shop/a ā { slug: ["a"] }
// /shop/a/b ā { slug: ["a", "b"] }
export default async function Shop({ params }) {
const { slug } = await params;
}Route groups
Wrap a folder in parentheses to organize routes without affecting the URL.
app
āāā (marketing)
ā āāā about
ā ā āāā page.tsx ā /about
ā āāā pricing
ā āāā page.tsx ā /pricing
āāā (shop)
āāā cart
āāā page.tsx ā /cartRoute groups let you apply different layouts to sections at the same URL level.
Private folders
Prefix a folder with an underscore to exclude it from routing.
app
āāā _components
ā āāā Button.tsx # not a route
āāā page.tsxParallel routes
Use @folder slots to render multiple pages in the same layout simultaneously.
app
āāā @modal
ā āāā default.tsx # fallback when no modal is active
ā āāā login
ā āāā page.tsx
āāā @analytics
ā āāā page.tsx
āāā layout.tsx # receives slots as props// app/layout.tsx
export default function Layout({ children, analytics, modal }) {
return (
<>
{children}
{analytics}
{modal}
</>
);
}Slots are passed as props and don't affect the URL. Add a default.tsx to each slot as a fallback.
Intercepting routes
Intercept a route to show it in a different context, like a modal.
app
āāā feed
ā āāā page.tsx
ā āāā (..)photo
ā āāā [id]
ā āāā page.tsx # intercepts /photo/[id] from /feed
āāā photo
āāā [id]
āāā page.tsx| Convention | Matches |
|---|---|
(.) | Segments on the same level |
(..) | Segments one level above |
(..)(..) | Segments two levels above |
(...) | Segments from the root |
Full-Stack AI Developer Roadmap
From HTML & CSS to working with AI models, all in one structured roadmap.