Next.js

Next.js App Router👨‍💻

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.

Key Takeaways

  • 1Routes are defined by folders in `app/`. A folder with a `page.tsx` becomes a URL segment — `app/blog/[slug]/page.tsx` maps to `/blog/hello-world`
  • 2Layouts (`layout.tsx`) wrap child routes and persist across navigations — they don't unmount or re-render when you move between sibling pages, making them ideal for sidebars, nav bars, and providers
  • 3Route groups `(groupName)` let you organize files and apply shared layouts without affecting the URL — `app/(auth)/login/page.tsx` renders at `/login`, not `/auth/login`
  • 4Special files have specific roles: `page.tsx` (route UI), `layout.tsx` (shared wrapper), `loading.tsx` (Suspense fallback), `error.tsx` (error boundary), `not-found.tsx` (404 UI), `route.tsx` (API endpoint)
  • 5Dynamic segments use bracket notation: `[slug]` for single segments, `[...slug]` for catch-all, `[[...slug]]` for optional catch-all — all receive params as props
  • 6Parallel routes (`@slot` folders) and intercepting routes (`(.)`, `(..)` conventions) enable advanced patterns like modals that degrade to full pages on hard refresh

Master next.js app router

Take the Next.js Full-Stack course with hands-on lessons and challenges.

Examples

Dashboard layout with persistent sidebar

tsx

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 — separate layouts for public and authenticated pages

tsx

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 routes with generateStaticParams for blog posts

tsx

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.

loading.tsx and error.tsx — declarative boundaries

tsx

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.

Parallel routes for a modal with URL state

tsx

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.

Catch-all routes for docs with nested sidebar

tsx

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.

Common Mistakes

Mistake:

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

Fix:

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.

Mistake:

Forgetting `default.tsx` in parallel route slots — navigating to a route that doesn't have a matching page in every slot causes a 404

Fix:

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.

Mistake:

Nesting `route.tsx` (API handler) and `page.tsx` in the same directory — Next.js does not allow both in the same route segment

Fix:

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.

Mistake:

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

Fix:

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.

Best Practices

  • Colocate components, utils, and tests inside route folders using underscore prefixes (`_components/`, `_lib/`) — folders starting with `_` are ignored by the router but keep related code next to the routes that use it
  • Use route groups aggressively to separate layout concerns: `(public)` for marketing pages, `(auth)` for login/signup, `(app)` for authenticated dashboard — each gets its own layout without polluting the URL structure
  • Add `loading.tsx` to every route segment that fetches data — it costs nothing, prevents blank screens during navigation, and gives users immediate visual feedback that the page is responding
  • Prefer `notFound()` from `next/navigation` over returning a manual 404 JSX — it triggers the nearest `not-found.tsx` boundary and sets the correct 404 HTTP status code, which matters for SEO
  • Keep `layout.tsx` free of heavy data fetching when the data is only needed by one child page — layouts persist across navigations, so unnecessary queries run repeatedly as users move between child routes
  • Use `generateStaticParams` for any dynamic route with a known set of values (blog slugs, product IDs, doc paths) — it pre-renders pages at build time and serves them from the CDN edge, which is dramatically faster than server-rendering on every request

Summary

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.

Practice Next.js with hands-on challenges

Learn next.js app router hands-on in your IDE

Interactive lessons and challenges on Stanza, practice in VS Code, Cursor, or the web.

Related Concepts

Related Cheatsheets

Master Next.js with Stanza

Interactive lessons and challenges, right in your code editor.

Check the free courses. No credit card.