Next.js App Router
Build routes, nested layouts, and loading states with file-based routing in the Next.js App Router.
TL;DR
- Create a route by adding a
page.tsxfile inside a folder. - Share UI across routes by adding a
layout.tsxat any level. - Await the
paramsandsearchParamsprops, because both are promises.
Routes From Folders
page.tsxAdd a page.tsx file to a folder to turn that folder path into a route.
// app/blog/page.tsx -> /blog
export default function Page() {
return <h1>Blog</h1>;
}Nested RoutesNest folders to build longer paths; each folder adds one segment to the URL.
app/
blog/
page.tsx // /blog
drafts/
page.tsx // /blog/draftssearchParamsRead the query string in a page by awaiting the searchParams prop.
export default async function Page({
searchParams,
}: {
searchParams: Promise<{ q?: string }>;
}) {
const { q } = await searchParams;
return <p>Results for {q}</p>;
}Layouts
layout.tsxWrap a route and all its children in shared UI that stays mounted.
// app/dashboard/layout.tsx
export default function Layout({
children,
}: {
children: React.ReactNode;
}) {
return <section>{children}</section>;
}Nested LayoutsLayouts stack, so a page renders inside every layout above it in the tree.
app/
layout.tsx // html, body
dashboard/
layout.tsx // sidebar
page.tsx // contenttemplate.tsxUse a template when the wrapper must reset its state on every navigation.
// app/dashboard/template.tsx
export default function Template({
children,
}: {
children: React.ReactNode;
}) {
return <div className="fade-in">{children}</div>;
}Special Files
loading.tsxShow instant fallback UI while the page for this segment is loading.
// app/dashboard/loading.tsx
export default function Loading() {
return <p>Loading dashboard...</p>;
}error.tsxCatch errors thrown in this segment and render a fallback in their place.
'use client';
export default function Error({
error,
}: {
error: Error;
}) {
return <p>Something went wrong.</p>;
}not-found.tsxRender custom 404 UI when a route calls notFound() or does not exist.
// app/not-found.tsx
export default function NotFound() {
return <h1>Page not found</h1>;
}Advanced Routing
(group)Group routes in a parenthesized folder to give them their own layout.
app/
(marketing)/
layout.tsx // marketing shell
page.tsx // /
(app)/
layout.tsx // app shell
dashboard/page.tsx@slotRender several pages in one layout by passing each slot in as a prop.
// app/layout.tsx with app/@modal/
export default function Layout({
children,
modal,
}: {
children: React.ReactNode;
modal: React.ReactNode;
}) {
return <>{children}{modal}</>;
}default.tsxGive every slot a fallback, which Next.js 16 requires at build time.
// app/@modal/default.tsx
export default function Default() {
return null;
}Tips
- Put shared navigation in a
layout.tsx, because layouts keep their state and do not re-render when you move between child pages. - Add a
loading.tsxto slow routes so users see a fallback immediately instead of waiting on a blank screen.
Warnings
- Reading
paramsorsearchParamswithoutawaitbreaks in Next.js 16, because synchronous access was removed. - Every parallel route slot needs a
default.tsxfile in Next.js 16, or the production build fails.
In Practice
Build a dashboard layout whose sidebar stays in place while the page content changes.
- The layout lives in the dashboard folder, so it wraps every dashboard route.
- Links in the sidebar navigate without reloading the layout itself.
- The children prop marks where each dashboard page renders.
- Because layouts stay mounted, the sidebar keeps its scroll position.
// app/dashboard/layout.tsx
import Link from 'next/link';
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="grid grid-cols-[200px_1fr]">
<aside>
<Link href="/dashboard">Overview</Link>
<Link href="/dashboard/orders">Orders</Link>
<Link href="/dashboard/settings">Settings</Link>
</aside>
<main>{children}</main>
</div>
);
}FAQ
The App Router is the routing system built on the app folder. Each folder is a URL segment, and a page.tsx file makes it a page. It supports layouts, Server Components, and streaming.
Use the App Router for new projects. The Pages Router still works, but new features like Server Components and 'use cache' only exist in the App Router.
A layout.tsx stays mounted when you navigate between its child pages, so its state survives. A template.tsx creates a fresh copy on every navigation, which resets state and re-runs effects.