The App Router is a ground-up rethink of how routing works in React applications. Instead of mapping files to URLs and wiring up data fetching separately, the App Router turns your folder structure into a component tree where layouts nest automatically, loading states are declarative, and error boundaries are just files you drop into a directory.
If you've used the Pages Router, forget getServerSideProps, getStaticProps, and the _app.tsx / _document.tsx dance. The App Router replaces all of that with a set of file conventions inside the app/ directory: page.tsx renders UI, layout.tsx wraps children and persists across navigations, loading.tsx shows a fallback during data fetching, error.tsx catches runtime failures, and not-found.tsx handles 404s. Every component is a Server Component by default, so you fetch data with async/await right in the component body.
The learning curve is real — especially around the server/client boundary and caching behavior — but the payoff is a routing system that scales from a marketing site to a complex SaaS dashboard without fighting the framework.
Master next.js app router
Take the Next.js Full-Stack course with hands-on lessons and challenges.
The dashboard layout fetches teams once and renders a sidebar that persists across all child routes. When a user navigates between /dashboard/settings and /dashboard/billing, only the {children} slot re-renders. The sidebar keeps its state, scroll position, and open/closed toggles.
Route groups wrap related routes in parentheses so they share a layout without adding a URL segment. The login page at app/(auth)/login/page.tsx renders at /login with a centered card layout, while the pricing page at app/(public)/pricing/page.tsx renders at /pricing with a full marketing header and footer.
Dynamic segments use [slug] bracket notation. generateStaticParams pre-renders all published posts at build time for fast loading. generateMetadata produces per-page SEO tags. The notFound() function triggers the closest not-found.tsx boundary. This is the standard pattern for any content-driven page: products, docs, user profiles.
Drop loading.tsx next to a page and Next.js wraps it in a Suspense boundary automatically. Drop error.tsx and you get a React error boundary. The analytics page shows a skeleton while data loads, and if fetchAnalytics throws, the error component renders with a retry button — without crashing the entire dashboard. The rest of the layout stays intact.
Clicking a photo link soft-navigates to /photos/photo/123 — but the intercepting route (.) catches it and renders the modal slot instead, overlaying the photo grid. The URL updates so the user can share it. If someone visits that URL directly (hard navigation), they see the full-page version. The default.tsx returns null when no modal is active, which is required for parallel routes.
Optional catch-all [[...slug]] matches /docs, /docs/getting-started, and /docs/api/auth/tokens with a single page component. The slug array gives you the full path hierarchy. Combined with not-found.tsx for missing pages and a sidebar fetched from the database, this is the pattern most documentation sites use.
Putting a `layout.tsx` and a `page.tsx` in the same route group folder and expecting the layout to only apply to that group — then being confused when sibling groups also pick it up
Each route group gets its own `layout.tsx`. A layout applies to everything inside its folder. If `app/(marketing)/layout.tsx` and `app/(app)/layout.tsx` both exist, they are independent. But if you put a layout in `app/` directly, it wraps all groups. Be intentional about which folder owns each layout.
Forgetting `default.tsx` in parallel route slots — navigating to a route that doesn't have a matching page in every slot causes a 404
Every `@slot` folder needs a `default.tsx` that returns what should render when there's no matching route for that slot. Usually it returns `null` or a fallback UI. Without it, Next.js doesn't know what to render for the unmatched slot during soft navigation.
Nesting `route.tsx` (API handler) and `page.tsx` in the same directory — Next.js does not allow both in the same route segment
A route segment is either a page or an API endpoint, not both. If you need `/api/posts` as an endpoint and `/posts` as a page, put `route.tsx` in `app/api/posts/` and `page.tsx` in `app/posts/`. They're different route segments.
Using `error.tsx` as a Server Component — it silently fails or throws because error boundaries must be Client Components to catch runtime errors and provide the reset function
Always add `'use client'` at the top of `error.tsx`. React error boundaries require component state and event handlers (the `reset` callback), which only work on the client. This is the one file where `'use client'` is mandatory, not optional.
The Next.js App Router replaces the Pages Router with a file-convention system where folders define routes and special files define behavior. `page.tsx` renders UI, `layout.tsx` wraps and persists across navigations, `loading.tsx` provides Suspense fallbacks, `error.tsx` catches runtime errors, and `not-found.tsx` handles 404s. Route groups organize layouts without affecting URLs. Dynamic segments (`[slug]`, `[...slug]`, `[[...slug]]`) handle parameterized routes. Parallel routes (`@slot`) and intercepting routes enable modal patterns. The mental model is straightforward once it clicks: your folder tree is your component tree, and each special file plugs into a specific slot in that tree.
Interactive lessons and challenges on Stanza, practice in VS Code, Cursor, or the web.
Interactive lessons and challenges, right in your code editor.
Check the free courses. No credit card.