How to generate Static Params in Nextjs?

In Next.js 14, static params allow you to pre-generate dynamic pages at build time. This is useful for optimizing performance, especially when dealing with a set of predefined paths, like product pages, blog posts, or in our case, recipe details. In this tutorial, we'll explore when and how to use static params, how to combine static and dynamic params, and handle catch-all segments.

Here’s how the folder structure looks for our Recipe App with static params:

src/
└── app/
    β”œβ”€β”€ recipes/
    β”‚   β”œβ”€β”€ [id]/
    β”‚   β”‚   └── page.tsx         # Dynamic route with static params
    β”‚   └── layout.tsx           # Layout for recipe pages
    └── categories/
        β”œβ”€β”€ [...slug]/
        β”‚   └── page.tsx         # Catch-all route with static params
        └── layout.tsx           # Layout for category pages

When to Use Static Params

Static params are a good choice when you have a limited set of dynamic routes that won’t change often. In our Recipe App, recipe detail pages are a perfect use case. You can pre-generate the pages for recipes like "chocolate-cake" or "pasta-alfredo" at build time.

Use Case: Pre-generating recipe detail pages for better performance and SEO.

Let’s set up static params for the /recipes/[id] route.


Setting Up Static Params

To generate static pages for specific recipes, we need to define static paths using the generateStaticParams function in Next.js 14 App Router. This function will return an array of params, allowing Next.js to pre-build pages for each recipe.

// src/app/recipes/[id]/page.tsx
import { fetch } from 'next/navigation';

// Define static paths for pre-generating pages
export async function generateStaticParams() {
  const recipes = await fetch('https://api.example.com/recipes').then(res => res.json());

  return recipes.map((recipe: { id: string }) => ({
    id: recipe.id, // Static params for each recipe
  }));
}

// Server-side component to render recipe details
export default async function RecipeDetail({ params }: { params: { id: string } }) {
  const recipe = await fetch(`https://api.example.com/recipes/${params.id}`).then(res => res.json());

  return (
    <section>
      <h2>{recipe.name}</h2>
      <p>{recipe.description}</p>
    </section>
  );
}
  • generateStaticParams() defines the static paths to be pre-built during the build process.
  • Each recipe is fetched from the API and mapped into a set of static params.
  • The component then renders the recipe based on the id param.

Final HTML output for /recipes/chocolate-cake:

<html lang="en">
  <body>
    <section>
      <h2>Chocolate Cake</h2>
      <p>A delicious chocolate cake recipe.</p>
    </section>
  </body>
</html>

Mixing Static and Dynamic Params

Sometimes, you may want to pre-generate some pages statically and leave others to be rendered dynamically. For example, you may have a small set of popular recipes that you want to pre-build, while allowing new recipes to be generated on-demand.

In Next.js 14, you can mix static and dynamic params by using the fallback feature. If a page isn’t pre-generated, Next.js will serve it dynamically.

// src/app/recipes/[id]/page.tsx
import { fetch } from 'next/navigation';

// Only pre-generate these popular recipes
export async function generateStaticParams() {
  const popularRecipes = await fetch('https://api.example.com/popular-recipes').then(res => res.json());

  return popularRecipes.map((recipe: { id: string }) => ({
    id: recipe.id,
  }));
}

// Dynamic rendering for non-static pages
export default async function RecipeDetail({ params }: { params: { id: string } }) {
  const recipe = await fetch(`https://api.example.com/recipes/${params.id}`).then(res => res.json());

  return (
    <section>
      <h2>{recipe.name}</h2>
      <p>{recipe.description}</p>
    </section>
  );
}

Using Catch-All Segments with Static Params

Catch-all segments allow you to create routes that match multiple levels of paths. In our Recipe App, this could be useful for handling nested categories, like /categories/desserts/chocolate or /categories/main-course/pasta.

We use a catch-all segment [...slug] to handle these nested paths.

// src/app/categories/[...slug]/page.tsx
export async function generateStaticParams() {
  const categories = await fetch('https://api.example.com/categories').then(res => res.json());

  return categories.map((category: { slug: string[] }) => ({
    slug: category.slug,
  }));
}

// Dynamic rendering for catch-all segments
export default function CategoryPage({ params }: { params: { slug: string[] } }) {
  const categoryPath = params.slug.join(' > ');

  return (
    <section>
      <h2>Category: {categoryPath}</h2>
      <p>Recipes in this category.</p>
    </section>
  );
}
  • The catch-all segment [...slug] allows for any number of path segments to be captured.
  • generateStaticParams() defines which nested category paths to pre-generate.
  • The CategoryPage component renders the category path dynamically based on the slug.

Final HTML output for /categories/desserts/chocolate:

<html lang="en">
  <body>
    <section>
      <h2>Category: desserts > chocolate</h2>
      <p>Recipes in this category.</p>
    </section>
  </body>
</html>

Performance Considerations with Static Params

Static params improve performance by pre-generating pages at build time, so users get fast, static content served directly from the CDN. However, it's essential to manage which pages you choose to generate statically, as generating too many pages can lead to longer build times.

Best Practice:

  • Pre-generate static pages for popular or frequently accessed content.
  • Use dynamic rendering for pages with high variability or less frequent access.

Summary

In Next.js 14 App Router, static params allow you to generate dynamic routes at build time for improved performance and SEO. By using generateStaticParams(), you can pre-build popular recipe pages while mixing in dynamic pages for flexibility. Catch-all segments offer powerful routing for nested paths like categories, making it easy to manage more complex URL structures.

Next.js
Clap here if you liked the blog