Dynamic Routes

Dynamic segments [param] for parameterized URLs like /blog/:slug and /users/:id.

Overview

Dynamic routes use [param] syntax to match variable segments. Each folder or file named [param] creates a URL that accepts any value for that segment and provides it via useParams().

PatternExample URLCreates URL?
[slug]/blog/hello-worldYes - dynamic creates URL
[id]/users/123Yes - dynamic creates URL
[category]/[slug]/blog/tech/hello-worldYes - multiple dynamic creates URL
useParams() is auto-imported - no import needed. Param names must match /^[a-zA-Z_][a-zA-Z0-9_]*$/.

Dynamic Segments

Wrap folder or file name in brackets [name]. Creates URL for any value.

app
blog
[slug]
page.tsx
products
[id]
page.tsx
users
[userId]
page.tsx
/blog/:slugRoutable
/products/:idRoutable
/users/:userIdRoutable
app/blog/[slug]/page.tsx
export default function BlogPost() {
  const { slug } = useParams<{ slug: string }>()

  return <h1>Post: {slug}</h1>
}
app/users/[id]/page.tsx
export default function UserProfile() {
  const { id } = useParams<{ id: string }>()
  const [user, setUser] = useState<{ name: string } | null>(null)

  useEffect(() => {
    fetchUser(id!).then(setUser)
  }, [id])

  if (!user) return null

  return <h1>{user.name}</h1>
}

Multiple Parameters

Multiple dynamic segments in one route. Each creates a URL part and becomes a property in useParams().

app
blog
[category]
[slug]
page.tsx
/blog/:category/:slugRoutable
app/blog/[category]/[slug]/page.tsx
export default function BlogPost() {
  const { category, slug } = useParams<{
    category: string
    slug: string
  }>()

  return (
    <div>
      <p>Category: {category}</p>
      <h1>Post: {slug}</h1>
    </div>
  )
}
URLparamsCreates URL?
/blog/tech/hello-world{ category: "tech", slug: "hello-world" }Yes
/blog/lifestyle/travel{ category: "lifestyle", slug: "travel" }Yes

Dynamic Segments in Layouts

Layouts can access dynamic params via useParams(). The layout itself does not create a URL.

app
blog
[slug]
layout.tsx
page.tsx
-Not Routable
/blog/:slugRoutable
app/blog/[slug]/layout.tsx
export default function BlogLayout({
  children,
}: {
  children: React.ReactNode
}) {
  const { slug } = useParams<{ slug: string }>()

  return (
    <div>
      <header>
        <h2>Post: {slug}</h2>
        <Link to="/blog">Back to blog</Link>
      </header>
      <main>{children}</main>
    </div>
  )
}

Flat File Dynamic Routes

Dynamic routes as flat files without folders. Each file creates a URL directly.

app
blog
[slug].tsx
products
[id].tsx
users
[userId].tsx
/blog/:slugRoutable
/products/:idRoutable
/users/:userIdRoutable
app/blog/[slug].tsx
export default function BlogPost() {
  const { slug } = useParams<{ slug: string }>()
  return <h1>Post: {slug}</h1>
}

Route Priority

Dynamic routes have lower priority than static routes. Static wins if both exist.

  1. Static routes - /blog/featured - creates URL, highest priority
  2. Dynamic segments - [slug] → /blog/:slug - creates URL
blog
featured
page.tsx
[slug]
page.tsx
/blog/featuredRoutable
/blog/:slugRoutable
URLMatched RouteCreates URL?
/blog/featuredfeatured/page.tsx - staticYes
/blog/hello-world[slug]/page.tsx - dynamicYes

Complete Example

Dynamic routes only - [param] patterns that create URLs.

app
blog
featured
page.tsx
[slug]
layout.tsx
page.tsx
[category]
[slug]
page.tsx
products
page.tsx
[id].tsx
users
[userId]
page.tsx
settings
page.tsx
/blog/featuredRoutable
-Not Routable
/blog/:slugRoutable
/blog/:category/:slugRoutable
/productsRoutable
/products/:idRoutable
/users/:userIdRoutable
/users/:userId/settingsRoutable
PatternExample URLCreates URL?
/blog/featured/blog/featuredYes - static
/blog/:slug/blog/hello-worldYes - dynamic creates URL
/blog/:category/:slug/blog/tech/hello-worldYes - multiple dynamic creates URL
/products/:id/products/123Yes - flat file dynamic creates URL
/users/:userId/settings/users/john/settingsYes - nested dynamic creates URL
Was this helpful?