How it works
The explanation, with examples you can run.
From folders to a component tree
app/ layout.tsx <html><body>… (the root layout, required) page.tsx / dashboard/ layout.tsx sidebar around every dashboard page loading.tsx shown while a dashboard page is loading page.tsx /dashboard [teamId]/ page.tsx /dashboard/acme, /dashboard/globex, … (marketing)/ pricing/page.tsx /pricing (the group adds nothing to the URL)For /dashboard/acme, the rendered tree is roughly:
<RootLayout> <DashboardLayout> <Suspense fallback={<DashboardLoading />}> <TeamPage params={Promise.resolve({ teamId: "acme" })} /> </Suspense> </DashboardLayout></RootLayout>loading.tsx is shorthand for that Suspense boundary, and error.tsx adds an error boundary in the same way. Because they sit at a particular level, a slow or failing page replaces only its own segment; the sidebar in the dashboard layout stays on screen.
Dynamic segments arrive as params, which in Next.js 16 is a promise you await (synchronous access was removed). generateStaticParams can list known values so those pages are prerendered at build time.
Layouts stay, pages change
A layout receives children (the segment below it) and wraps it. When the user navigates between two pages under the same layout, Next.js does a client-side transition: it fetches only the segments that differ and keeps the shared layouts mounted, with their client state and scroll positions. This is why a layout cannot read searchParams or the current pathname directly; it doesn't rerender when they change. Read those in the page, or in a client component with useSearchParams and usePathname.
Links rendered with <Link> are prefetched when they enter the viewport, so the data for the next segment is often in the browser before the click. How much is prefetched depends on what the route can prerender, which is the subject of the rendering topics later in this path.
Colocation
Only page and route files are publicly reachable, so components, tests and helpers can live next to the route that uses them. Folders starting with _ are private and never become routes. Route groups (name) let different sections have different root layouts; navigating between two root layouts is a full page load, since there is no shared frame to keep.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.