Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Your First Next.js App  ›  Lesson

Dynamic Segments

Next.js Routing Basics 14 minA folder name in square brackets matches any value in that part of the URL, and the page receives that value through its params.

Dynamic Segments

Trailhead lists 40 trails, and each needs its own page: /trails/misty-ridge, /trails/fox-hollow, /trails/cedar-falls and so on. Creating 40 folders would be absurd, and every new trail would need another. One folder with a special name handles them all.

The rule

Square brackets catch the value; params hands it to the page.

Name a folder with square brackets and it matches any value in that position of the URL:

app/trails/[slug]/page.tsx   # /trails/misty-ridge, /trails/fox-hollow, ...

The word inside the brackets becomes a key in the page's params. In current Next.js, params is a promise, so you await it:

// app/trails/[slug]/page.tsx
import { notFound } from "next/navigation";
import { getTrail } from "@/lib/trails";

export default async function TrailPage({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;      // "misty-ridge"
  const trail = await getTrail(slug);
  if (!trail) notFound();             // a real 404 page
  return <h1>{trail.name}</h1>;
}

notFound() stops rendering and shows the 404 page, so a mistyped URL does not produce a broken page.

Two variations cover deeper URLs:

Folder Matches params for /docs/a/b
[slug] exactly one segment not matched
[...slug] one or more segments { slug: ["a", "b"] }
[[...slug]] zero or more segments { slug: ["a", "b"] }, and also matches /docs

A fixed folder beats a dynamic one at the same level: if both app/trails/new/page.tsx and app/trails/[slug]/page.tsx exist, /trails/new goes to new.

The shortcut

To predict what a page receives, line the URL up against the folders. Wherever a bracketed folder sits, the matching piece of the URL becomes the value, under the name inside the brackets.

/trails/fox-hollow/photos against the foldersStep 1 of 4
  1. Line them up

    trails ↔ trails, fox-hollow ↔ [slug], photos ↔ photos.

The trap in older tutorials is reading params.slug directly without await. In current Next.js, params is a promise; await it first.

Drills

Answer fast — trust the rule.

quick drill

Which folder serves every URL of the form /trails/<name>?

quick drill

For /trails/cedar-falls, what does await params give the page in app/trails/[slug]/page.tsx?

quick drill

Which folder matches both /guides/winter and /guides/winter/gear?

quick drill

The slug matches no trail. What should the page do?

Remember

  • Square brackets catch the value; params (awaited) hands it to the page.
  • Shortcut: line the URL up against the folders; brackets name the value.
  • Trap: params is a promise in current Next.js, and a fixed folder beats a dynamic one.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainOne file, every trail

Trailhead has 40 trails, each at a URL like /trails/misty-ridge. Explain how you serve all of them with one file, how the page finds out which trail was asked for, and what it should do when the slug matches no trail.