How AI is powering better personalization in e-commerce [with Vercel]. Sign up now

Dynamic route works in dev but fails in production with next build

18 repliesLast updated: Nov 29, 2025

Can anyone here think of a reason that a dynamic route might work in dev mode but not in production mode when running
next build && next start
? We have a project we are working on that has a dynamic
path
being created in the query to sanity, and we are using a wildcard
[path].tsx
to catch those routes. The query seems to work fine, and in dev we can get to all the pages using this route. But in production we get empty pages for
/page1
, and 404s for
/page1/childpage
AI Update

This is a classic Next.js static generation issue! The problem is almost certainly that your dynamic routes aren't being pre-rendered at build time. Here's what's happening:

The Root Cause:

In development mode (next dev), Next.js generates pages on-demand for every request. But in production (next build && next start), Next.js uses static generation by default, which means pages need to be either:

Since you're using a catch-all route like [path].tsx, you need to implement getStaticPaths() (Pages Router) or generateStaticParams() (App Router) to tell Next.js which paths to pre-render.

The Solution:

For Pages Router ([path].tsx):

export async function getStaticPaths() {
  const paths = await client.fetch(
    `*[_type == "yourType" && defined(path)][].path`
  );

  return {
    paths: paths.map((path) => ({ params: { path } })),
    fallback: 'blocking', // or true, see below
  };
}

export async function getStaticProps({ params }) {
  const { path } = params;
  const data = await client.fetch(
    `*[_type == "yourType" && path == $path][0]`,
    { path }
  );
  
  return {
    props: { data },
    revalidate: 60, // Optional: ISR
  };
}

For App Router (app/[path]/page.tsx):

export async function generateStaticParams() {
  const paths = await client.fetch(
    `*[_type == "yourType" && defined(path)][].path`
  );

  return paths.map((path) => ({ path }));
}

Understanding Fallback Options:

The fallback property in getStaticPaths is crucial:

Why You're Seeing Different Behaviors:

For Catch-All Routes Specifically:

If you're using [...path].tsx to capture nested routes like /page1/childpage, make sure your params structure matches:

// For [...path].tsx (catch-all)
paths: allPaths.map((pathString) => ({
  params: { path: pathString.split('/') } // Array for catch-all
}))

// For [path].tsx (single segment)
paths: allPaths.map((pathString) => ({
  params: { path: pathString } // String for single segment
}))

The key takeaway: production builds require explicit path generation. Without getStaticPaths or generateStaticParams, Next.js doesn't know which dynamic routes to create at build time!

Show original thread
18 replies

Was this answer helpful?

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Related contributions