Skip to content

Next.js - Dynanic API Routes

Next.js - Dynamic Routes and Data Fetching

Section titled “Next.js - Dynamic Routes and Data Fetching”

Dynamic routes allow you to create pages from dynamic data, such as blog posts, product details, or user profiles, where the URL structure depends on parameters.

In the App Router, dynamic segments are defined using square brackets [] in folder names. For example, app/posts/[slug]/page.tsx creates routes like /posts/my-first-post, /posts/learning-nextjs, etc.

Let’s build a simple blog where each post has its own page based on a unique ‘slug’.

Step 1: Define Data Source

Create a utility file to simulate fetching blog post data. Create lib/posts.ts (create the lib directory in the project root if it doesn’t exist):

lib/posts.ts
export interface Post {
slug: string;
title: string;
content: string;
date: string;
}
// Simulate a database or API call
const posts: Post[] = [
{
slug: 'getting-started-with-nextjs',
title: 'Getting Started with Next.js',
content: 'Next.js is a React framework for production...',
date: '2024-01-10',
},
{
slug: 'dynamic-routing-explained',
title: 'Dynamic Routing Explained',
content: 'Learn how dynamic routes work in the App Router...',
date: '2024-01-15',
},
];
// Function to get all possible slugs (for static generation)
export async function getAllPostSlugs(): Promise<{ slug: string }[]> {
// In a real app, fetch this from your CMS or database
return posts.map(post => ({ slug: post.slug }));
}
// Function to get post data by slug
export async function getPostData(slug: string): Promise<Post | null> {
// In a real app, fetch this from your CMS or database
const post = posts.find(p => p.slug === slug);
return post || null;
}

Step 2: Create the Dynamic Page Component

Create the file app/posts/[slug]/page.tsx. The folder name [slug] indicates that slug is a dynamic parameter.

app/posts/[slug]/page.tsx
import { getPostData, getAllPostSlugs } from '@/lib/posts'; // Using path alias '@'
import { notFound } from 'next/navigation';
import { Metadata } from 'next';
interface PostPageProps {
params: {
slug: string; // The dynamic segment value
};
}
// Function to generate Metadata dynamically
export async function generateMetadata({ params }: PostPageProps): Promise<Metadata> {
const post = await getPostData(params.slug);
if (!post) {
return { title: 'Post Not Found' };
}
return { title: post.title };
}
// Function to generate static paths at build time
export async function generateStaticParams() {
const slugs = await getAllPostSlugs();
// Returns an array like: [{ slug: 'post-1' }, { slug: 'post-2' }]
return slugs;
}
// The Page component
export default async function PostPage({ params }: PostPageProps) {
const post = await getPostData(params.slug);
// Handle cases where the post data isn't found
if (!post) {
notFound(); // Renders the nearest not-found.tsx page or a default 404
}
return (
<article>
<h1>{post.title}</h1>
<p><time dateTime={post.date}>{post.date}</time></p>
<div>{post.content}</div>
{/* Add a link back if desired */}
{/* <Link href="/posts">Back to Posts List</Link> */}
</article>
);
}
  • [slug] Folder: Defines a dynamic route segment named slug.
  • params Prop: The page component receives a params prop containing the actual value of the dynamic segment(s) for the current request (e.g., { slug: 'getting-started-with-nextjs' }).
  • generateStaticParams(): (Optional but recommended for static generation) This function tells Next.js which possible values of slug exist at build time. Next.js will pre-render a static HTML page for each path returned by this function. If a user requests a path not generated here, Next.js might try to generate it on-demand or show a 404, depending on configuration (dynamicParams option in layout.js or page.js, default is true).
  • Data Fetching: The PostPage component is a Server Component, so it directly fetches data using await getPostData(params.slug). No need for getStaticProps or getServerSideProps like in the Pages Router.
  • notFound(): A helper function from next/navigation used to gracefully handle cases where data for the requested slug doesn’t exist, rendering a 404 page.
  • generateMetadata(): (Optional) Allows generating page metadata (like title, description) dynamically based on the fetched data.

Run the development server:

npm run dev
  1. Open http://localhost:3000/posts/getting-started-with-nextjs in your browser. You should see the content for the first blog post.

  2. Open http://localhost:3000/posts/dynamic-routing-explained. You should see the content for the second blog post.

  3. Try navigating to a non-existent slug like http://localhost:3000/posts/invalid-slug. You should see a 404 Not Found page (either a custom not-found.tsx if you created one, or the default Next.js 404 page).