Dynamic Routes and Parameter Handling
Dynamic Routes and Parameter Handling
Section titled “Dynamic Routes and Parameter Handling”Introduction
Section titled “Introduction”Dynamic routes allow you to create pages that match a range of URLs, enabling data-driven content like blog posts, product pages, or user profiles. This topic covers how to create dynamic routes and access route parameters in Next.js.
Why do we need this?
Section titled “Why do we need this?”Hardcoding a separate page for every possible URL (like every blog post or product) is impractical. Dynamic routes let you create a single page template that can display content for many different URLs based on parameters.
Problem Statement
Section titled “Problem Statement”Without dynamic routes, you would need to create a new file for every piece of content, leading to maintenance nightmares and inconsistencies. Updating the design would require changing hundreds of similar files.
Real World Story
Section titled “Real World Story”You’re building an e-commerce site with 10,000 products. Instead of creating 10,000 separate product pages, you create one dynamic route pages/products/[id].js that can display any product based on the id parameter.
Real World Analogy
Section titled “Real World Analogy”Think of dynamic routes like a template letter:
- Instead of writing a unique letter for every customer, you create one template with placeholders
- You fill in the placeholders (name, address, etc.) for each specific letter
- Similarly, a dynamic route is a template that fills in content based on URL parameters
Visual Explanation
Section titled “Visual Explanation”Dynamic routes use brackets to define parameterized segments in the file path.
Mermaid Diagram 1: Dynamic Route Matching
Section titled “Mermaid Diagram 1: Dynamic Route Matching”flowchart TD A[Request: /products/123] --> B{Match to pages/products/[id].js} B -->|Yes| C[Extract params: { id: "123" }] C -->|No| D[Check other routes] D -->|Match dynamic| E[Process accordingly] E -->|No match| F[Return 404]Internal Working
Section titled “Internal Working”When a request matches a dynamic route:
- Next.js identifies the dynamic segments (enclosed in square brackets)
- It extracts the values from the URL and puts them in the
paramsobject - The page component receives these parameters via:
getStaticProps({ params })getServerSideProps({ params })getStaticPaths({ params })(for SSG)useRouter()hook (client-side)router.query(in page component)
- The component uses these parameters to fetch or compute the appropriate content
Mermaid Diagram 2: Data Flow in Dynamic Routes
Section titled “Mermaid Diagram 2: Data Flow in Dynamic Routes”sequenceDiagram participant Browser as Browser participant NextJS as Next.js participant Data as Data Source Browser->>NextJS: GET /products/123 NextJS->>NextJS: Match to pages/products/[id].js NextJS->>NextJS: Extract params { id: "123" } alt Static Generation NextJS->>Data: Fetch product 123 at build time Data-->>NextJS: Return product data else Server-Side Rendering NextJS->>Data: Fetch product 123 on request Data-->>NextJS: Return product data end NextJS->>NextJS: Render component with data NextJS-->>Browser: Send HTML and JS Browser->>Browser: Hydrate React components Browser->>User: Display product pageArchitecture
Section titled “Architecture”Dynamic routes in Next.js follow the same file-system routing principles as static routes, with the addition of parameter extraction. The framework handles:
- Parameter extraction from URLs
- Passing parameters to data fetching functions
- Client-side hydration of parameter values
- Proper 404 handling for non-matching parameters
- Integration with
getStaticPathsfor pre-rendering dynamic routes
Syntax
Section titled “Syntax”Single Parameter
Section titled “Single Parameter”export default function Post({ params }) { return <div>Post ID: {params.id}</div>;}Multiple Parameters
Section titled “Multiple Parameters”export default function BlogPost({ params }) { return <div>Month: {params.month}, Year: {params.year}</div>;}Catch-all (One or More Segments)
Section titled “Catch-all (One or More Segments)”export default function Path({ params }) { return <div>Path: {params.slug.join('/')}</div>;}Optional Catch-all (Zero or More Segments)
Section titled “Optional Catch-all (Zero or More Segments)”export default function Path({ params }) { const path = params.slug ? `/${params.slug.join('/')}` : '/'; return <div>Path: {path}</div>;}Basic Example
Section titled “Basic Example”Creating a dynamic route for blog posts:
import { useRouter } from 'next/router';
export default function Post() { const router = useRouter(); const { slug } = router.query;
// Simulated data fetch const post = { welcome: { title: 'Welcome', content: 'First post!' }, 'nextjs-routing': { title: 'Routing Guide', content: 'Learn routing.' } }[slug] || { title: 'Not Found', content: 'Post does not exist.' };
return ( <div> <h1>{post.title}</h1> <div>{post.content}</div> {!router.isFallback && ( <p><a href="/blog">← Back to Blog</a></p> )} </div> );}Intermediate Example
Section titled “Intermediate Example”Handling numeric IDs and converting to numbers:
import { useRouter } from 'next/router';
export default function Product() { const router = useRouter(); const { id } = router.query; const numericId = parseInt(id, 10);
const products = { 1: { name: 'Laptop', price: 999.99 }, 2: { name: 'Mouse', price: 29.99 } };
const product = products[numericId] || { name: 'Not Found', price: 0 };
return ( <div> <h2>{product.name}</h2> <p>Price: ${product.price.toFixed(2)}</p> </div> );}Advanced Example
Section titled “Advanced Example”Using getStaticProps and getStaticPaths for static generation:
export default function Post({ post }) { return ( <div> <h1>{post.title}</h1> <p>{post.content}</p> </div> );}
export async function getStaticProps({ params }) { const { id } = params; const res = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`); if (!res.ok) return { notFound: true }; const post = await res.json(); return { props: { post }, revalidate: 60 };}
export async function getStaticPaths() { return { paths: [ { params: { id: '1' } }, { params: { id: '2' } }, { params: { id: '3' } } ], fallback: 'blocking' };}Production Example
Section titled “Production Example”In production, dynamic routes are handled based on your data fetching strategy:
- Static Generation (SSG): Pre-rendered at build time (ideal for blogs)
- Server-Side Rendering (SSR): Rendered on each request (ideal for frequent data changes)
- Incremental Static Regeneration (ISR): Revalidated in the background (ideal for occasionally updated content)
- Client-Side Rendering (CSR): Data fetched on the client (ideal for user-specific dashboards)
Folder Structure
Section titled “Folder Structure”Common patterns for dynamic routes:
pages/├── blog/│ └── [slug].js → /blog/:slug├── products/│ ├── [id].js → /products/:id│ └── [id]/│ └── reviews.js → /products/:id/reviews├── users/│ └── [username].js → /:username└── api/ └── [resource]/ └── [id].js → /api/[resource]/:idBest Practices
Section titled “Best Practices”- Choose the right parameter name: Use descriptive names like
[slug]or[postId]instead of generic[id]when it adds clarity - Validate parameters: Especially for numeric IDs, parse and check for validity
- Handle missing data: Return
{ notFound: true }from data fetching functions when data doesn’t exist - Use appropriate fetching strategy: Match your data fetching method (SSG/SSR/ISR/CSR) to your data’s update frequency
- Leverage
getStaticPaths: Define which paths to pre-render for static generation - Consider fallback behavior: Choose between
false,true, or'blocking'based on your UX needs - Keep components focused: Each dynamic route page should handle its specific data fetching and presentation
- Optimize for performance: Use
revalidateingetStaticPropsfor ISR to balance freshness and performance - Handle edge cases: Consider what happens with empty parameters, special characters, or unexpected values
- Test thoroughly: Verify both existing and non-existing paths work as expected
Common Mistakes
Section titled “Common Mistakes”- Forgetting to handle missing parameters: Leads to undefined values and potential errors
- Not validating parameter types: Treating string “123” as number 123 without conversion can cause issues
- Incorrect
getStaticPathsconfiguration: Results in 404s for valid paths or excessive rebuilds - Using dynamic routes for static content: Wastes server resources when static generation would suffice
- Ignoring error handling in data fetching: Leads to unhandled promise rejections and crash loops
- Using the same parameter name in nested routes: Creates confusion when accessing values
- Assuming parameter values are numbers: Remember that
paramsvalues are always strings - Not handling empty arrays in catch-all:
[[...slug]]gives undefined for root,[]for single segment with[...slug] - Confusing
paramsandquery:paramsfor route parameters,queryfor query strings (e.g.,?id=123) - Over-nesting dynamic routes: Makes URLs long and complex; consider if the nesting is truly necessary
Performance Notes
Section titled “Performance Notes”- Static Generation (SSG): Fastest for end-users (HTML served from CDN)
- Incremental Static Regeneration (ISR): Good balance of freshness and performance (background regeneration)
- Server-Side Rendering (SSR): Slightly slower per request but always up-to-date
- Client-Side Rendering (CSR): Quickest initial HTML but requires client-side data fetching (can cause loading states)
- Parameter extraction overhead: Negligible (simple string parsing)
- Data fetching bottleneck: Usually the limiting factor in performance, not route matching
- Cacheability: SSG/ISR responses can be cached by CDNs; SSR responses typically have shorter cache times
- Prefetching:
next/linkprefetches JavaScript for linked routes (but not the data)
Security Notes
Section titled “Security Notes”- Input validation: Always validate parameters before using them in database queries or file system operations
- Sanitize user input: If parameters come from untrusted sources (e.g., user-generated URLs), sanitize to prevent injection
- Authorization checks: Ensure users have permission to access the requested resource (e.g., user can only view their own profile)
- Rate limiting: Especially important for public API endpoints with dynamic parameters to prevent abuse
- Error handling: Avoid leaking stack traces or internal errors in responses; use proper error status codes
- Secure headers: Implement security headers (CSP, HSTS) via middleware or headers API
- Redirect safety: Validate redirect URLs to prevent open redirect vulnerabilities
- Parameter pollution: Though rare in path parameters, be aware of duplicate parameter names in query strings
- Dependency checks: Regularly audit dependencies for vulnerabilities (
npm auditoryarn audit)
SEO Considerations
Section titled “SEO Considerations”- Descriptive parameters: Use meaningful names (e.g.,
[slug]instead of[id]) for readable URLs - URL structure: Keep URLs clean and hierarchical (e.g.,
/blog/2023/01/my-postvs/posts/123) - Canonical tags: Prevent duplicate content by specifying preferred URLs for paginated or filtered views
- Trailing slashes: Be consistent (configure via
next.config.js->trailingSlash) - Pagination: Use
rel="next"andrel="prev"for paginated series - Internationalization: Consider language and region in parameters (e.g.,
[lang]/[country]/[slug]) - Structured data: Include JSON-LD markup in dynamic pages for rich snippets (reviews, products, events)
- Metadata: Use
next/headto set dynamic titles, descriptions, and open graph tags - Internal linking: Link between related dynamic content to improve crawlability
- Server-side rendering preference: For SEO-critical content, favor SSG/SSR over CSR to ensure crawlers see content
- Sitemap generation: Dynamically generate sitemaps based on your routes and update frequency
- Robots.txt: Control crawler access to sensitive or duplicate content areas
Interview Questions
Section titled “Interview Questions”- How do you create a dynamic route for a blog post by slug in Next.js?
- What is the difference between
[id].jsand[[...id]].jsin the pages directory? - How do you access route parameters in a page component using the
useRouterhook? - What is the purpose of
getStaticPathsin Next.js? - How would you handle a dynamic route that can accept zero or more path segments?
- How do you pass data to a dynamic page using
getStaticProps? - What happens if you don’t provide a
fallbackingetStaticPaths? - How would you create a catch-all route that matches all paths under a directory?
- How do you validate dynamic route parameters to prevent security issues?
- How does Next.js handle numeric parameters in dynamic routes?
- What is the difference between
getStaticPropsandgetServerSidePropsfor data fetching? - How can you implement authentication for dynamic routes (e.g., user-specific profiles)?
- What are the performance implications of using dynamic routes versus static routes?
-
Which file creates the route
/blog/2023/05? a)pages/blog/[year]/[month].jsb)pages/blog/2023/05.jsc)pages/blog/[year]/05.jsd)pages/blog/[year]/[month]/[day].jsAnswer
-
What does
pages/[...slug].jsmatch? a) Exactly one path segment b) Zero or more path segments c) One or more path segments d) Exactly two path segmentsAnswer
-
What does
pages/[[...slug]].jsmatch? a) Exactly one path segment b) Zero or more path segments c) One or more path segments d) Exactly two path segmentsAnswer
-
How do you access a dynamic route parameter in
getStaticProps? a)props.paramsb)this.paramsc) The first argument togetStaticPropsd) Theparamsproperty of the context objectAnswer
-
Which file would create the route
/user/john/settings? a)pages/user/[name]/settings.jsb)pages/user/[name]/[setting].jsc)pages/user/[name].jsd)pages/user/[name]/[setting]/[value].edAnswer
-
What is the value of
paramsfor the route/blog/2023/05/10matchingpages/blog/[year]/[month]/[day].js? a){ year: "2023", month: "05", day: "10" }b){ year: 2023, month: 5, day: 10 }c){ "0": "2023", "1": "05", "2": "10" }d){ path: "/blog/2023/05/10" }Answer
-
How do you handle a dynamic route that may not have matching data (e.g., invalid ID)? a) Return
{ notFound: true }fromgetStaticProps/getServerSidePropsb) Throw an error in the page component c) Return{ redirect: { destination: '/404', permanent: false } }d) All of the aboveAnswer
-
What is the purpose of the
fallbackoption ingetStaticPaths? a) To specify what to do when a requested path is not in thepathsarray b) To define the default layout for dynamic routes c) To set the cache duration for static regeneration d) To enable or disable API routesAnswer
-
Which file creates a catch-all route for the
docssection? a)pages/docs/[...slug].jsb)pages/docs/[[...slug]].jsc)pages/[...docs]/[...slug].jsd)pages/[...slug]/docs.jsAnswer
-
How would you access a dynamic route parameter in an API route? a)
req.paramsb)req.queryc)req.bodyd)req.headersAnswer
Practice Exercise
Section titled “Practice Exercise”- Create a new Next.js project called
dynamic-routing-exercise - Create a dynamic route for blog posts:
pages/blog/[slug].js - Implement
getStaticPropsto fetch post data based on slug - Implement
getStaticPathsto define which paths to pre-render - Create a list of blog posts on the homepage linking to individual posts
- Add error handling for non-existent posts (show 404 page)
- Create a dynamic route for products with multiple parameters:
pages/products/[category]/[id].js - Implement navigation between product list and individual products
- Test the dynamic routes in the development server
- Verify that accessing
/blog/nonexistentshows the 404 page
Mini Project
Section titled “Mini Project”Build a simple movie database application:
- Create a dynamic route for movies:
pages/movies/[id].js - Fetch movie data from a public API (like OMDB API) in
getStaticProps - Implement
getStaticPathsto handle a predefined set of movie IDs - Create a movie list page (
/movies) that links to individual movies - Add search functionality that filters movies by title (client-side)
- Create a dynamic route for movie reviews:
pages/movies/[id]/reviews/[reviewId].js - Implement infinite scroll or pagination for movie lists
- Add movie details: title, year, genre, director, plot, poster
- Implement error handling for invalid movie IDs
- Add a “Random Movie” button that redirects to a random movie in the database
- Create an API route for submitting reviews:
api/movies/[id]/reviews(POST) - Ensure all pages are responsive and accessible
- Test the application thoroughly in development mode
Summary
Section titled “Summary”In this topic, you learned how to create dynamic routes in Next.js to handle data-driven content. You understand how to define dynamic route parameters, access them in your components and data fetching functions, and handle various types of dynamic routes including single parameters, multiple parameters, catch-all, and optional catch-all routes.
Cheat Sheet
Section titled “Cheat Sheet”# Dynamic Route Syntaxpages/posts/[id].js → /posts/:idpages/blog/[year]/[month].js → /blog/:year/:monthpages/[slug].js → /:slugpages/[...slug].js → /:slug* (one or more segments)pages/[[...slug]].js → /:slug?* (zero or more segments)
# Accessing Parameters// In getStaticProps/getServerSidePropsexport async function getStaticProps({ params }) { const { id } = params; // ...}
// In page component (pages/router)import { useRouter } from 'next/router';const router = useRouter();const { slug } = router.query;
// Or with useParams (app router)import { useParams } from 'next/navigation';const { slug }';const { slug } = useParams();
// In API routesexport default function handler(req, res) { const { id } = req.query; // ...}
// getStaticPaths Exampleexport async function getStaticPaths() { return { paths: [ { params: { id: '1' } }, { params: { id: '2' } } ], fallback: 'blocking' // true/false/'blocking' };}
// Error Handling// In getStaticProps/getServerSidePropsif (!data) { return { notFound: true };}
// In page componentimport { notFound } from 'next/navigation';if (!data) { notFound();}Related Topics
Section titled “Related Topics”- Catch-all and Optional Catch-all Routes
- API Routes and Middleware
- Data Fetching Methods (getStaticProps, getServerSideProps, getStaticPaths)
- Static Generation vs Server-Side Rendering
- Incremental Static Regeneration (ISR)
- Route Groups (App Router)
- Dynamic Routes with TypeScript