Overview

The App Router is the default in Next.js 15. Routes are folders under app/, and the file names in each folder describe what that segment does. A folder becomes a URL segment, a page.tsx makes it routable, a layout.tsx wraps every child below it, and a handful of other reserved filenames cover loading, errors, and not-found states. The router is server-first; react-server-components is the rendering model underneath.

Put pages in app/, one folder per segment

Each folder under app/ is a URL segment. The folder app/posts/[slug]/page.tsx serves /posts/:slug. Folders without a page.tsx do not produce a route; they only contribute layouts or co-located files.

app/
  layout.tsx        // root layout (required)
  page.tsx          // "/"
  posts/
    page.tsx        // "/posts"
    [slug]/
      page.tsx      // "/posts/:slug"

Use [param] for a single dynamic segment, [...slug] for a catch-all, and [[...slug]] for an optional catch-all. Type params in the page signature; Next.js 15 passes them as a Promise that must be awaited.

Use layout.tsx for shells, page.tsx for routes

A layout.tsx wraps every page below it and re-renders only when the layout’s own data changes. Put the nav, providers, theme, and auth context here. A page.tsx is the leaf that owns the route’s main content.

// app/dashboard/layout.tsx
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="dashboard">
      <Sidebar />
      <main>{children}</main>
    </div>
  );
}

The root app/layout.tsx is the only required file in app/. It must render <html> and <body> and is the right place for the <Metadata> defaults (see nextjs-metadata-api).

Group routes without changing the URL

Wrap a folder name in parentheses to create a route group: app/(marketing)/about/page.tsx serves /about, not /marketing/about. Groups exist for organizing layouts, not for URLs.

Use groups to give different sections their own layouts:

app/
  (marketing)/
    layout.tsx     // marketing chrome
    about/page.tsx
    pricing/page.tsx
  (app)/
    layout.tsx     // authenticated chrome
    dashboard/page.tsx

Two segments in different groups can share the same URL prefix without sharing a layout. This replaces most of the layout-juggling that Pages Router needed.

Render parallel routes with named slots

Parallel routes let a single layout render two independent panes that each have their own loading and error states. Mark a folder with @: app/@feed/page.tsx and app/@sidebar/page.tsx are both passed to the layout as props.

// app/layout.tsx
export default function Layout({
  children,
  feed,
  sidebar,
}: {
  children: React.ReactNode;
  feed: React.ReactNode;
  sidebar: React.ReactNode;
}) {
  return (
    <>
      <main>{children}</main>
      <aside>{sidebar}</aside>
      <section>{feed}</section>
    </>
  );
}

Parallel routes are the right primitive for dashboards with independent panels and for modals layered over a base page. Pair them with intercepting routes for modal navigation.

Intercept routes for modals over a base page

An intercepting route renders one route in the position of another. The convention uses (.), (..), or (...) prefixes that mirror relative imports. Use them when a user clicks a thumbnail and a photo opens as a modal over the gallery, but a direct visit to the same URL shows the full photo page.

app/
  photos/
    page.tsx              // "/photos" gallery
    [id]/page.tsx         // "/photos/:id" full page
  @modal/
    (.)photos/[id]/page.tsx  // modal over "/photos"

The intercepted view runs inside the parallel @modal slot when the user arrives via client navigation; the canonical page still renders on a hard load or share.

Migrate from Pages Router incrementally

app/ and pages/ can coexist. Move one route at a time and keep the rest on Pages until the migration is done.

  • getServerSideProps becomes an async server component that awaits its data inline.
  • getStaticProps plus getStaticPaths becomes a server component with generateStaticParams.
  • _app.tsx splits into app/layout.tsx (providers) and per-segment layouts.
  • API routes in pages/api/ move to route.ts handlers under app/; see nextjs-route-handlers.
  • Mutations move from API routes to server actions; see nextjs-server-actions.

Keep the migration on a branch until every route renders correctly, then delete pages/.