Dynamic Routing in Next.js

Creating dynamic routes with URL parameters

🔀 What is Dynamic Routing?

Dynamic routing allows you to create pages with variable URL segments. Use square brackets in folder names to capture URL parameters and display different content based on the URL.


// app/blog/[slug]/page.js
export default function Post({ params }) {
  return <h1>Post: {params.slug}</h1>
}
                                    

Dynamic Route Types

📝

Single Parameter

One dynamic segment

[id] [slug]
🔗

Multiple Parameters

Nested dynamic segments

[category]/[id] Multiple levels
🎯

Optional Parameters

Optional catch segments

[[slug]] May be empty
🌟

Catch-All Routes

Multiple segments

[...slug] Array of params

🔹 Single Dynamic Segment

Create a dynamic route by wrapping a folder name in square brackets. The parameter name becomes available in your page component through the params prop.

🔸 Folder Structure

app/
└── blog/
    └── [slug]/
        └── page.js        → /blog/hello-world
                          → /blog/nextjs-tutorial

🔸 Accessing Parameters

// app/blog/[slug]/page.js
export default function BlogPost({ params }) {
  return (
    <div>
      <h1>Blog Post</h1>
      <p>Reading: {params.slug}</p>
    </div>
  )
}

// URL: /blog/hello-world
// params.slug = "hello-world"

🔸 Fetching Data with Parameters

// app/blog/[slug]/page.js
async function getPost(slug) {
  const res = await fetch(`https://api.example.com/posts/${slug}`)
  return res.json()
}

export default async function BlogPost({ params }) {
  const post = await getPost(params.slug)
  
  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </article>
  )
}

🔹 Multiple Dynamic Segments

Nest multiple dynamic segments to create complex URL structures. Each segment becomes a separate parameter accessible in your component.

🔸 Folder Structure

app/
└── shop/
    └── [category]/
        └── [product]/
            └── page.js    → /shop/electronics/laptop
                          → /shop/clothing/shirt

🔸 Using Multiple Parameters

// app/shop/[category]/[product]/page.js
export default function Product({ params }) {
  return (
    <div>
      <h1>Product Page</h1>
      <p>Category: {params.category}</p>
      <p>Product: {params.product}</p>
    </div>
  )
}

// URL: /shop/electronics/laptop
// params.category = "electronics"
// params.product = "laptop"

🔹 Generating Static Paths

For static site generation, use generateStaticParams to pre-render dynamic routes at build time. This improves performance by creating pages ahead of time.

🔸 Generate Static Params

// app/blog/[slug]/page.js
export async function generateStaticParams() {
  const posts = await fetch('https://api.example.com/posts')
    .then(res => res.json())
  
  return posts.map((post) => ({
    slug: post.slug,
  }))
}

export default async function BlogPost({ params }) {
  const post = await getPost(params.slug)
  return <h1>{post.title}</h1>
}

// Generates pages at build time:
// /blog/first-post
// /blog/second-post
// /blog/third-post

🔹 Generating Metadata

Create dynamic page titles and meta tags based on URL parameters. This is essential for SEO and social media sharing.

🔸 Dynamic Metadata

// app/blog/[slug]/page.js
export async function generateMetadata({ params }) {
  const post = await getPost(params.slug)
  
  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: [post.image],
    },
  }
}

export default async function BlogPost({ params }) {
  const post = await getPost(params.slug)
  return <article>{post.content}</article>
}

🔹 Linking to Dynamic Routes

Use the Link component to navigate to dynamic routes. Pass the parameter values directly in the href prop for clean, readable code.

🔸 Static Links

import Link from 'next/link'

export default function BlogList() {
  return (
    <div>
      <Link href="/blog/hello-world">
        Hello World Post
      </Link>
      <Link href="/blog/nextjs-guide">
        Next.js Guide
      </Link>
    </div>
  )
}

🔸 Dynamic Links

import Link from 'next/link'

export default function BlogList({ posts }) {
  return (
    <div>
      {posts.map(post => (
        <Link key={post.id} href={`/blog/${post.slug}`}>
          {post.title}
        </Link>
      ))}
    </div>
  )
}

🔹 Handling Not Found

Handle invalid dynamic parameters gracefully by returning a 404 page when content doesn't exist. Use notFound() function for proper error handling.

🔸 Not Found Handling

import { notFound } from 'next/navigation'

async function getPost(slug) {
  const res = await fetch(`https://api.example.com/posts/${slug}`)
  if (!res.ok) return null
  return res.json()
}

export default async function BlogPost({ params }) {
  const post = await getPost(params.slug)
  
  if (!post) {
    notFound()
  }
  
  return <h1>{post.title}</h1>
}

🔹 Best Practices

Follow these guidelines when working with dynamic routes:

  • Use descriptive names: [slug], [id], [username] instead of [param]
  • Validate parameters: Check if data exists before rendering
  • Handle errors: Use notFound() for missing content
  • Generate static paths: Pre-render pages when possible
  • Add metadata: Dynamic titles and descriptions for SEO
  • Type safety: Use TypeScript for parameter types

🧠 Test Your Knowledge

How do you create a dynamic route segment?