Next.jsReactApp RouterRouting

Next.js Routing Guide: App Router Patterns

Learn the current Next.js App Router model: static routes, dynamic segments, catch-all routes, layouts, route groups, parallel routes, and route handlers.

·Updated ·11 min read·Counting...
Next.js Routing Guide: App Router Patterns

When learning Next.js routing today, start with the App Router. The Pages Router still exists, especially in older projects, but new tutorials, new applications, and most current framework patterns are centered on the app/ directory.

The core model is straightforward: folders describe URL segments, page.tsx creates a route, and layout.tsx wraps routes below it.

Basic App Router structure

app/
  page.tsx              -> /
  about/
    page.tsx            -> /about
  blog/
    [slug]/
      page.tsx          -> /blog/:slug

The main differences from older examples:

  • Pages live in app/**/page.tsx.
  • Layouts are persistent wrappers defined by layout.tsx.
  • Server Components are the default in App Router.

For component boundary decisions, read Next.js Server vs Client Components.

Static routes

A fixed route is just a folder with a page file:

app/
  pricing/
    page.tsx

The URL is /pricing:

export default function PricingPage() {
  return <h1>Pricing</h1>
}

This is the right model for landing pages, about pages, tools, dashboards, and most top-level product sections.

Dynamic routes

Use square brackets when part of the path is a variable:

app/blog/[slug]/page.tsx

In current Next.js versions, params is commonly typed and awaited as a promise:

export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params
  return <div>{slug}</div>
}

Older tutorials often show params as a synchronous object. Check the version and documentation before copying code into a new app.

Catch-all routes

[...slug] matches multiple path segments:

app/docs/[...slug]/page.tsx

It can match:

/docs/setup
/docs/react/server-components

The value becomes an array. If the route should also match the parent path itself, use optional catch-all syntax:

app/docs/[[...slug]]/page.tsx

That can match both /docs and /docs/setup.

Layouts are not just wrapper components

Layouts persist across route transitions under the same segment:

app/
  dashboard/
    layout.tsx
    page.tsx
    analytics/
      page.tsx

/dashboard and /dashboard/analytics share the dashboard layout. This is useful for:

  • Dashboard navigation
  • Documentation sidebars
  • Account settings shells
  • Multi-section tools

If a layout needs local loading and error boundaries, add files such as loading.tsx and error.tsx in the right segment.

Route Groups

Route Groups use parentheses:

app/
  (marketing)/
    about/
      page.tsx

The group name does not appear in the URL, so the final path is still /about.

Use groups to organize code by business area, layout family, or team ownership. Be careful not to create conflicting URLs from different groups. Also remember that switching between different root layouts may trigger a full page load.

Parallel Routes

Parallel Routes use named slots:

app/
  dashboard/
    layout.tsx
    @team/
      page.tsx
    @analytics/
      page.tsx

The layout receives those slots as props:

export default function Layout({
  children,
  team,
  analytics,
}: {
  children: React.ReactNode
  team: React.ReactNode
  analytics: React.ReactNode
}) {
  return (
    <>
      {children}
      {team}
      {analytics}
    </>
  )
}

This is an advanced pattern for dashboards, deep-linkable modals, or independently loading panes. A normal blog, marketing site, or CRUD interface usually does not need it.

Route Handlers

API routes in App Router live in app/api/**/route.ts:

export async function GET() {
  return Response.json({ ok: true })
}

Route Handlers are useful for lightweight APIs, webhooks, form endpoints, and server-side adapters that belong inside the Next.js app.

If you are choosing between Route Handlers, client fetch, Server Actions, and backend APIs, read Next.js Server Actions vs Fetch: How to Choose.

When Pages Router still appears

You will still see pages/ in older codebases, gradual migrations, and packages built around historical conventions. That does not make those projects wrong. It means the routing model must be read in context.

For new pages and new learning material, prefer the App Router model so the code does not become obsolete quickly.

Subscribe to FreeMac

Weekly picks: free Mac software reviews, trusted source updates, alternatives, and low-friction guides.