Next.js - Dynamic Route not working in Production Mode when running `Next Build && Next Start`
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:
- Pre-rendered at build time, OR
- Configured to generate on-demand with proper fallback handling
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:
fallback: false- Returns 404 for any path not generated at build timefallback: true- Generates pages on-demand, but requires loading state handlingfallback: 'blocking'- Generates pages on-demand and waits before serving (no loading state needed)
Why You're Seeing Different Behaviors:
/page1showing empty: The page is rendering butgetStaticPropsisn't fetching data because the path wasn't pre-rendered/page1/childpageshowing 404: Next.js doesn't know this route exists at all
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!
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.