How to Implement Dynamic Routing in Next.js?

Introduction

Dynamic routing in Next.js allows you to create pages with dynamic paths based on data, making your application more flexible and powerful. This guide explores how to set up dynamic routing in Next.js, including dynamic routes, nested routes, and catch-all routes.

1. Dynamic Routing

Dynamic routing enables the creation of pages that depend on the data provided at runtime. Instead of hardcoding paths, you define routes using dynamic segments, which Next.js maps to specific pages dynamically.

2. Setting Up Dynamic Routes
 

Creating Dynamic Routes

To create dynamic routes, use square brackets [param] in your file names. For example, to create a route for individual blog posts, you can create a file named [id].js inside the pages/posts directory.

Example

Create the File Structure

pages/
  posts/
    [id].js

Add Dynamic Route Logic

// pages/posts/[id].js
import { useRouter } from 'next/router';
const Post = () => {
  const router = useRouter();
  const { id } = router.query; // Access the dynamic parameter
  return (
    <div>
      <h1>Post {id}</h1>
      {/* Fetch and display post content based on `id` */}
    </div>
  );
};
export default Post;

Fetching Data for Dynamic Routes

To fetch data for dynamic routes, use getStaticProps and getStaticPaths for Static Site Generation (SSG) or getServerSideProps for Server-Side Rendering (SSR).

Example with getStaticProps and getStaticPaths

Generate Static Paths

// pages/posts/[id].js

export async function getStaticPaths() {
  const res = await fetch('https://jsonplaceholder.typicode.com/posts');
  const posts = await res.json();
  // Generate paths based on data
  const paths = posts.map(post => ({
    params: { id: post.id.toString() },
  }));
  return { paths, fallback: 'blocking' }; // Use 'blocking' or 'true' for fallback
}
export async function getStaticProps({ params }) {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}`);
  const post = await res.json();
  return {
    props: { post },
  };
}
const Post = ({ post }) => (
  <div>
    <h1>{post.title}</h1>
    <p>{post.body}</p>
  </div>
);
export default Post;

3. Nested Dynamic Routes

For nested dynamic routes, create nested folder structures.

Example

File Structure for Nested Routes

pages/
  posts/
    [id]/
      index.js
      comments.js

Fetching Data for Nested Routes

// pages/posts/[id]/comments.js
import { useRouter } from 'next/router';
const Comments = ({ comments }) => {
  const router = useRouter();
  const { id } = router.query;
  return (
    <div>
      <h1>Comments for Post {id}</h1>
      <ul>
        {comments.map(comment => (
          <li key={comment.id}>{comment.body}</li>
        ))}
      </ul>
    </div>
  );
};
export async function getServerSideProps({ params }) {
  const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${params.id}/comments`);
  const comments = await res.json();

  return {
    props: { comments },
  };
}
export default Comments;

4. Catch-All Routes

Catch-all routes handle multiple dynamic segments. Use [...params] to catch all paths.

Example

Create a Catch-All Route

// pages/posts/[...slug].js
import { useRouter } from 'next/router';
const Post = () => {
  const router = useRouter();
  const { slug } = router.query; // slug is an array of parameters
  return (
    <div>
      <h1>Post {slug.join('/')}</h1>
      {/* Fetch and display post content based on `slug` */}
    </div>
  );
};
export default Post;

5. Dynamic Routes with API Routes

Dynamic API routes can be set up similarly using [param] in the pages/api directory.

Example

Create API Route

// pages/api/posts/[id].js
export default async function handler(req, res) {
  const { id } = req.query;
  const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
  const post = await response.json();
  res.status(200).json(post);
}

6. Best Practices for Dynamic Routing

  • Use getStaticPaths for static generation: Use getStaticPaths to pre-render pages with dynamic segments.
  • Leverage fallback options: Choose appropriate fallback behavior (false, true, or 'blocking') based on your needs.
  • Validate data: Ensure you validate and handle errors for dynamic routes and API responses.

Summary

Dynamic routing in Next.js offers powerful ways to create flexible and scalable applications. By using dynamic, nested, and catch-all routes, you can build complex routing structures that adapt to your data. Employ these techniques to enhance your Next.js applications and provide a robust user experience.