Next.js
0. Next.js App Router, File-Based Routing
Next.js App Router, File-Based Routing
The App Router (since Next.js 13) uses the app/ directory instead of pages/ (the legacy Pages Router). Each folder inside app/ corresponds to a URL segment, and special files within that folder define the UI and behavior for that specific segment.
1. Convention files
| File | Role |
|---|---|
page.tsx | Unique UI content for that route; mandatory to make the route publicly accessible via URL |
layout.tsx | Shared UI wrapping page.tsx and all nested child routes. Does not re-render when navigating between child routes under the same layout, preserving UI state (e.g. sidebar, nav) |
loading.tsx | UI displayed while page.tsx (or nested data fetching) is loading, automatically wrapped in <Suspense> |
error.tsx | UI displayed when an error is thrown within that route subtree; must be a Client Component ('use client') |
not-found.tsx | UI displayed when notFound() is invoked or no route matches |
route.ts | Route Handler (API endpoint); cannot coexist with page.tsx in the same folder at the same level |
2. Route groups: (group)
- Folders wrapped in parentheses, such as
app/(marketing)/about/page.tsx, do not appear in the URL path (the URL remains/about). - Used to organize routes by purpose (e.g. assigning distinct layouts to
(marketing)and(dashboard)) without altering URL structure.
3. Nested layouts
- Layouts in parent folders wrap layouts in child folders, creating a hierarchical tree. For example,
app/layout.tsx(root layout, required, containing<html>/<body>) wrapsapp/dashboard/layout.tsx, which in turn wrapsapp/dashboard/settings/page.tsx. - When transitioning between routes under the same layout (e.g. from
/dashboard/settingsto/dashboard/profile),dashboard/layout.tsxdoes not re-mount; only the innerpage.tsxcomponent swaps out.
4. Dynamic routes
| Syntax | Meaning | Matching URL Example |
|---|---|---|
[id] | Single dynamic segment | /products/[id] matches /products/5 |
[...slug] | Catch-all, requires at least 1 segment | /docs/[...slug] matches /docs/a/b/c, does not match /docs |
[[...slug]] | Optional catch-all | /docs/[[...slug]] matches both /docs and /docs/a/b/c |
- Access dynamic segment values via the
paramsprop inpage.tsx/layout.tsx, for example{ params }: { params: { id: string } }.
