Next JS Dynamic Routes
Dynamic Routes in Next.js enable you to create pages that can change based on URL parameters, allowing for a more flexible routing structure. This feature is particularly useful for applications that require user-specific data, such as blogs, e-commerce sites, and dashboards.
1. Understanding Dynamic Routes
Dynamic routes allow you to create pages that respond to variable parts of a URL. Instead of creating a separate file for each URL, you can define a pattern that matches multiple routes using square brackets ([]
). This capability is part of Next.js's file-based routing system.
2. Creating Dynamic Routes
a. Basic Syntax
To create a dynamic route, you need to define a file name or folder name in your app/
directory (or pages/
in earlier versions) using square brackets. The content inside the brackets will act as a variable that can be accessed in your component.
Example Structure:
app/
products/
[id]/
page.js
In this example:
- The
products/[id]/
folder defines a dynamic route whereid
is a variable that will match any product ID in the URL.
b. Accessing Dynamic Route Parameters
To access the dynamic route parameter, you can use the useParams
hook from Next.js. This hook provides the values of the dynamic segments in the URL.
Example of Using Dynamic Routes:
// app/products/[id]/page.js
import { useParams } from 'next/navigation';
export default function ProductPage() {
const { id } = useParams(); // Access the dynamic route parameter
// Fetch product data using the id
// For example, you might fetch from an API using the id
// const product = await fetchProduct(id);
return (
<div>
<h1>Product ID: {id}</h1>
{/* Render product details */}
</div>
);
}
In this example:
useParams
retrieves theid
from the URL.- You can then use this
id
to fetch the corresponding product details from an API or a data source.
3. Nested Dynamic Routes
Next.js allows you to create nested dynamic routes by combining dynamic segments with static segments. This is particularly useful for applications with hierarchical data structures.
Example Structure:
app/
blog/
[slug]/
comments/
[commentId]/
page.js
In this structure:
- The first dynamic segment
[slug]
represents a blog post. - The second dynamic segment
[commentId]
represents comments related to that blog post.
Accessing Nested Dynamic Parameters:
// app/blog/[slug]/comments/[commentId]/page.js
import { useParams } from 'next/navigation';
export default function CommentPage() {
const { slug, commentId } = useParams(); // Access dynamic route parameters
return (
<div>
<h1>Blog Post: {slug}</h1>
<h2>Comment ID: {commentId}</h2>
{/* Render comment details */}
</div>
);
}
4. Catch-All Routes
Next.js also supports catch-all routes, which allow you to match multiple segments in the URL. This is useful for more complex routing scenarios where you want to capture multiple levels of parameters.
Catch-All Syntax:
To create a catch-all route, use double square brackets ([[...param]]
).
Example Structure:
app/
docs/
[[...slug]]/
page.js
In this example, slug
can capture one or more segments. So URLs like /docs/
, /docs/guide
, and /docs/guide/getting-started
would all be matched.
Accessing Catch-All Route Parameters:
// app/docs/[[...slug]]/page.js
import { useParams } from 'next/navigation';
export default function DocsPage() {
const { slug } = useParams(); // Access the catch-all parameter
return (
<div>
<h1>Documentation</h1>
<p>Slug: {slug ? slug.join('/') : 'Root Document'}</p>
{/* Render documentation based on slug */}
</div>
);
}
5. Dynamic Routing with API Routes
Dynamic routes can also be used with API routes. You can create dynamic API endpoints that accept parameters, allowing for CRUD operations based on those parameters.
Example Structure:
app/
api/
users/
[id].js
In this example, the API endpoint /api/users/[id]
can be accessed to perform actions on user data based on the user ID.
Example API Handler:
// app/api/users/[id].js
export async function GET(request, { params }) {
const { id } = params; // Access the dynamic route parameter
// Fetch user data based on id
const user = await fetchUserById(id);
return new Response(JSON.stringify(user), {
headers: { 'Content-Type': 'application/json' },
});
}
6. Fallback Pages with Static Generation
When using dynamic routes with Static Site Generation (SSG), you may want to specify fallback behavior for pages that haven’t been generated at build time. This is particularly useful for large datasets.
Example with Fallback:
// app/products/[id]/page.js
import { getStaticPaths, getStaticProps } from 'next';
export async function getStaticPaths() {
// Fetch all product IDs to generate paths
const paths = await fetchProductIds();
return {
paths: paths.map((id) => ({ params: { id } })),
fallback: true, // Enable fallback behavior
};
}
export async function getStaticProps({ params }) {
const product = await fetchProduct(params.id);
return {
props: { product },
};
}
export default function ProductPage({ product }) {
if (!product) {
return <div>Loading...</div>; // Show loading state while fallback is active
}
return (
<div>
<h1>{product.name}</h1>
{/* Render product details */}
</div>
);
}
7. Using Dynamic Routes with Client-Side Navigation
Next.js provides a Link component for client-side navigation, which supports dynamic routes. You can construct URLs dynamically based on the parameters you want to pass.
Example Usage:
import Link from 'next/link';
function ProductList({ products }) {
return (
<div>
<h1>Products</h1>
<ul>
{products.map((product) => (
<li key={product.id}>
<Link href={`/products/${product.id}`}>
{product.name}
</Link>
</li>
))}
</ul>
</div>
);
}
Summary
Dynamic Routes in Next.js allow developers to create flexible, parameterized URL paths that can be used to render dynamic content. Key points about dynamic routes include:
Creating Dynamic Routes: Use square brackets (
[]
) to define dynamic segments in file names, which will correspond to variable parts of the URL.Accessing Parameters: Use the
useParams
hook to access dynamic route parameters within the component.Nested Dynamic Routes: You can create nested dynamic routes using additional folders and square brackets for multiple segments.
Catch-All Routes: Use double square brackets (
[[...param]]
) to create catch-all routes that can capture multiple segments.Dynamic API Routes: Create dynamic API endpoints to handle parameterized requests.
Static Generation with Fallback: Combine dynamic routes with SSG to generate pages at build time, with the option for fallback behavior for paths not generated.
Client-Side Navigation: Utilize the Link component to navigate between dynamic routes seamlessly.
By using dynamic routes effectively, you can create sophisticated, user-driven applications that respond to varying user input and data dynamically, enhancing the overall user experience.