Dynamic Routing and Catch-All Routes in Next.js

Dynamic Routing and Catch-All Routes in Next.js

·

4 min read

Dynamic routing in Next.js allows you to create flexible routes that adapt to user input. This feature is particularly useful for building dynamic applications like blogs, e-commerce sites, and user-specific dashboards. Additionally, Next.js provides robust support for handling non-existent routes through custom 404 pages and catch-all routes.


What is Dynamic Routing?

Dynamic routing enables you to define routes where part of the URL can change dynamically. For example:

  • /product/[id] can match URLs like /product/1, /product/2 or /product/special-item.

Difference Between next/navigation and next/router

Both next/navigation and next/router offer routing utilities, but they cater to different environments within Next.js.

next/navigation

  • Scope: Specifically designed for the App Router (introduced in Next.js 13).

  • Features:

    • useParams: Access dynamic route parameters.

    • useSearchParams: Access query parameters.

    • useRouter: Provides navigation methods like push, replace, and back.

    • notFound: Programmatically trigger 404 pages.

    • redirect: Redirect users to a specific URL.

Recommended Use: When using the App Router for building routes in the src/app directory.

next/router

  • Scope: Designed for the Pages Router (traditional routing system in Next.js).

  • Features:

    • useRouter: Access the router object for navigation and dynamic route handling.

    • query: Access route parameters and query strings.

    • prefetch: Prefetch pages for better performance.

  • Recommended Use: When building applications in the src/pages directory.


Creating Dynamic Routes

Step 1: Define a Dynamic Route File

To create a dynamic route, use square brackets ([ ]) in your file or folder name within the pages or app directory. For example:

src/app/products/[id]/page.tsx

Step 2: Access the Dynamic Parameter

Inside your dynamic route, you can access the parameter using params (in the App Router) or query (in the Pages Router).

App Router Example:

interface ProductPageProps {
  params: { id: string };
}

export default function ProductPage({ params }: ProductPageProps) {
  return <h1>Product ID: {params.id}</h1>;
}

Pages Router Example:

import { useRouter } from 'next/router';

export default function ProductPage() {
  const router = useRouter();
  const { id } = router.query;

  return <h1>Product ID: {id}</h1>;
}

Inside your dynamic route, you can access the parameter using the params object provided by Next.js.

Example Using App Router:

import { notFound } from 'next/navigation';

interface ProductPageProps {
  params: { id: string };
}

export default function ProductPage({ params }: ProductPageProps) {
  if (!params.id) {
    notFound();
  }

  return <h1>Product ID: {params.id}</h1>;
}

Alternatively, use the useParams hook from next/navigation:

import { useParams } from 'next/navigation';

export default function ProductPage() {
  const params = useParams();

  if (!params.id) {
    return <h1>404 - Product Not Found</h1>;
  }

  return <h1>Product ID: {params.id}</h1>;
}

Catch-All Routes

Catch-all routes match multiple URL segments and are defined using [...param] in the file or folder name.

Example:

src/app/docs/[...slug]/page.tsx

Handling Catch-All Parameters:

interface DocsPageProps {
  params: { slug: string[] };
}

export default function DocsPage({ params }: DocsPageProps) {
  const slugPath = params.slug.join('/');

  return <h1>Viewing: {slugPath}</h1>;
}

This route will match paths like:

  • /docs

  • /docs/getting-started

  • /docs/tutorials/advanced


Optional Catch-All Routes

You can make a catch-all route optional by adding a question mark (?) in the file name:

This matches both /docs and any nested paths under /docs.

By adding a question mark (?) after the ...slug part, you can make the catch-all segment optional, meaning the route will match even if there's no additional path segment after the base URL.

pages/docs/[...slug]?
This route will match:
- /docs
- /docs/post-title
- /docs/category/article-name
  • Usage:

    This is particularly useful for creating fallback pages or handling situations where a user might access a URL with or without additional parameters.


Handling 404 Errors

Next.js allows you to create a custom 404 page for non-existent routes.

Step 1: Create a 404 Page

In the App Router:

src/app/not-found.tsx

In the Pages Router:

src/pages/404.tsx

Step 2: Define the Custom 404 Page

export default function NotFound() {
  return <h1>404 - Page Not Found</h1>;
}

With the App Router, you can also use the notFound() function to programmatically trigger a 404:

import { notFound } from 'next/navigation';

export default function ProductPage({ params }: { params: { id: string } }) {
  if (!params.id) {
    notFound();
  }

  return <h1>Product ID: {params.id}</h1>;
}

Practical Use Cases

  1. Blogs:

    • /blog/[slug] for articles with unique slugs.
  2. E-Commerce:

    • /products/[id] for individual product pages.
  3. Documentation:

    • /docs/[...slug] for structured documentation paths.
  4. Custom 404 Pages:

    • Enhance user experience with branded 404 pages.

Conclusion

Dynamic and catch-all routes in Next.js provide a flexible and powerful way to build dynamic applications. By understanding how to create and use these routes effectively, you can handle a wide variety of use cases, from user-specific pages to structured documentation paths. Start exploring dynamic routing today to unlock the full potential of your Next.js applications!