Next.js App Router (app/)

Introduced in Next.js 13, the App Router powers the React Server Components architecture. Every folder inside app/ defines a route, and a page.js file inside that folder makes the route publicly accessible.

  • app/page.jswww.site.com/
  • app/about/page.jswww.site.com/about
  • app/dashboard/settings/page.jswww.site.com/dashboard/settings

Only page.js exposes a URL; additional files (for example components.js, styles.css) remain private.

Magic Files for UI States

The App Router reserves specific filenames to simplify common UI patterns:

  • layout.js — wraps descendant pages (ideal for navigation shells).
  • loading.js — renders automatically while data loads.
  • error.js — displays when the page throws.
  • not-found.js — custom 404 screen.

1. Nested Routes (The Basics)

Folders set the URL path. Place a page.js inside to publish the route.

app/
├── page.js               -> www.site.com/
├── about/
│   └── page.js           -> www.site.com/about
└── dashboard/
    ├── page.js           -> www.site.com/dashboard
    └── settings/
        └── page.js       -> www.site.com/dashboard/settings

2. Dynamic Routes (Params)

Use square brackets when the segment varies at runtime (blog posts, user profiles, and so on).

app/
└── blog/
    └── [slug]/           -> matches /blog/1, /blog/hello-world
        └── page.js

Access the parameter directly from the page component. In recent Next.js versions params is a Promise, so await it.

// app/blog/[slug]/page.js
export default async function BlogPost({ params }) {
  const slug = (await params).slug; // "hello-world"
  return <h1>Reading Post: {slug}</h1>;
}

3. API Routes (Route Handlers)

Route handlers replace pages/api/*.js by defining route.js files under app/api/.

  • Handles raw HTTP verbs (GET, POST, PUT, DELETE).
  • Conflict warning: a folder cannot contain both page.js and route.js; Next.js would not know whether to serve UI or JSON.
app/
└── api/
    └── users/
        └── route.js      -> endpoint: /api/users
import { NextResponse } from "next/server";

export async function GET() {
  const users = [{ id: 1, name: "Alice" }];
  return NextResponse.json(users);
}

export async function POST(request) {
  const body = await request.json();
  return NextResponse.json({ message: "User created", data: body });
}

4. Search Params (Query Strings)

Query string values appear in the searchParams prop that Next.js injects into page.js components. They are not available in layout.js.

// URL: www.site.com/shop?sort=desc
export default function Shop({ searchParams }) {
  const sortOrder = searchParams.sort; // "desc"
  return <p>Sorting by: {sortOrder}</p>;
}

5. Advanced Routing Patterns

Next.js recognises naming conventions that alter routing without changing the URL.

Route Groups (folder)

Organise routes or apply scoped layouts without affecting the path.

app/
├── (marketing)/
│   ├── layout.js       -> layout specific to marketing pages
│   └── about/
│       └── page.js     -> URL remains /about
└── (shop)/
    ├── layout.js       -> layout specific to shop pages
    └── cart/
        └── page.js     -> URL remains /cart

Private Folders _folder

Folders prefixed with an underscore are ignored by the router. Store collocated utilities here.

app/
└── dashboard/
    ├── _components/    -> not a route
    │   └── button.js
    └── page.js

Catch-All Segments [...slug]

Match variable depth URLs, returning each segment in an array. Use [[...slug]] to make the segment optional (handles / as well).

// app/docs/[...slug]/page.js
export default function DocPage({ params }) {
  return <div>Path: {params.slug.join(" / ")}</div>;
}

6. Navigation Helpers

Use Link instead of <a> to benefit from prefetching.

import Link from "next/link";

<Link href="/dashboard">Go to Dashboard</Link>;

useRouter for Programmatic Navigation

Client components can push routes via the App Router navigation hooks.

"use client";
import { useRouter } from "next/navigation";

export default function LoginButton() {
  const router = useRouter();
  return <button onClick={() => router.push("/dashboard")}>Login</button>;
}

Summary Checklist

Feature Syntax URL Result
Basic route folder/page.js /folder
Dynamic route folder/[id]/page.js /folder/123
Catch-all folder/[...slug]/page.js /folder/a/b/c
Route group (group)/page.js / (folder ignored)
Private folder _utils/ (never routed)
API route folder/route.js /folder (returns JSON)

Parallel routes: @folder(slots) -> Each defined slot automatically becomes a prop in its corresponding layout.tsx file.


This site uses Just the Docs, a documentation theme for Jekyll.