This Next.js build error occurs when you try to cache dynamic route segments without proper revalidation configuration. The error indicates that routes with dynamic parameters like [slug] or [id] cannot use indefinite caching because their content is user-specific or request-dependent.
This error appears in Next.js applications when the framework detects a conflict between your caching strategy and the use of dynamic route segments. Next.js distinguishes between static routes (which can be pre-rendered and cached indefinitely) and dynamic routes (which contain variable path segments like [userId] or [postId]). The error specifically occurs when Next.js tries to apply Full Route Cache to pages with dynamic segments without an appropriate revalidation strategy. Dynamic routes are rendered at request time by default and cannot be cached indefinitely because their content depends on runtime parameters. Next.js sets a Cache-Control header of "private, no-cache, no-store, max-age=0, must-revalidate" for dynamically rendered pages to prevent user-specific data from being cached improperly. This protection mechanism ensures that user-specific or request-dependent data doesn't get served to the wrong users. The error is Next.js' way of preventing potential security and correctness issues that could arise from indefinite caching of dynamic content.
Export a dynamic configuration to tell Next.js how to handle the route. For pages that must be dynamically rendered, add this to your page file:
// app/blog/[slug]/page.tsx
export const dynamic = 'force-dynamic';
export default function BlogPost({ params }: { params: { slug: string } }) {
// Your component code
}This explicitly opts the route out of Full Route Cache and Data Cache, ensuring it renders on every request. Alternative options include:
- dynamic = 'auto' (default): Cache when possible
- dynamic = 'force-static': Force static rendering (will error if dynamic APIs are used)
- dynamic = 'error': Force static rendering and throw error if dynamic
If you want to pre-render specific dynamic routes at build time, implement generateStaticParams():
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
const posts = await fetchAllPosts();
return posts.map((post) => ({
slug: post.slug,
}));
}
export default function BlogPost({ params }: { params: { slug: string } }) {
// Your component code
}This pre-generates pages at build time for the returned params. For ISR support, you must return an empty array or use dynamic = 'force-static'.
Add a revalidate value to enable Incremental Static Regeneration, allowing pages to be regenerated periodically:
// app/blog/[slug]/page.tsx
export const revalidate = 3600; // Revalidate every hour (in seconds)
export async function generateStaticParams() {
// Return empty array to enable ISR for all params
return [];
}
export default function BlogPost({ params }: { params: { slug: string } }) {
// Your component code
}Common revalidate values:
- 3600: 1 hour
- 86400: 24 hours
- false: Cache indefinitely (only works with static routes)
- 0: Never cache, always revalidate
If you're using the experimental "use cache" directive, remove it from pages that access dynamic data:
// BEFORE (causes error)
'use cache';
export default function Page({ params }: { params: { id: string } }) {
return <div>{params.id}</div>;
}
// AFTER (fixed)
export default function Page({ params }: { params: { id: string } }) {
return <div>{params.id}</div>;
}The "use cache" directive cannot be used with request-specific arguments like params, searchParams, or cookies(). These resolve at runtime and cannot be cached during the build phase.
Control what happens when a dynamic segment is visited that wasn't generated with generateStaticParams:
// app/blog/[slug]/page.tsx
export const dynamicParams = true; // Default: generate on-demand
// or
export const dynamicParams = false; // Return 404 for unknown params
export async function generateStaticParams() {
return [
{ slug: 'post-1' },
{ slug: 'post-2' },
];
}With dynamicParams = true, visiting /blog/post-3 will generate the page on-demand. With false, it returns a 404.
For specific fetch requests, configure caching individually instead of at the route level:
export default async function Page({ params }: { params: { id: string } }) {
// This fetch will be cached
const staticData = await fetch('https://api.example.com/static', {
cache: 'force-cache'
});
// This fetch will NOT be cached
const dynamicData = await fetch(`https://api.example.com/user/${params.id}`, {
cache: 'no-store'
});
return <div>...</div>;
}Cache options:
- force-cache: Cache indefinitely (default for fetch)
- no-store: Never cache
- no-cache: Cache but revalidate before use
Check your next.config.js for conflicting cache settings:
// next.config.js
module.exports = {
experimental: {
// Ensure this doesn't conflict with your route configs
cacheComponents: false, // May conflict with dynamic routes
},
};Also verify your deployment platform (Vercel, etc.) isn't enforcing conflicting cache policies. Review the build logs to see which routes are being statically generated vs. dynamically rendered.
Understanding Next.js caching layers is crucial: Full Route Cache (server-side, stores rendered HTML), Data Cache (server-side, stores fetch results), Router Cache (client-side, stores route segments), and Request Memoization (server-side, deduplicates requests during a render pass). Using dynamic = 'force-dynamic' or revalidate = 0 skips both Full Route Cache and Data Cache.
For Next.js 15+, be aware that the caching behavior has evolved significantly. The framework now has better automatic detection of dynamic data usage, but explicit configuration is still recommended for production applications. If you're migrating from Pages Router to App Router, note that getStaticPaths is replaced by generateStaticParams, and the behavior differs slightly.
When using multiple dynamic segments (e.g., /[category]/[slug]), the child generateStaticParams function executes once for each set of params the parent generates. The params object contains populated params from the parent, which can be used to generate child params.
For build performance, limit the number of pages pre-rendered with generateStaticParams. Consider returning only popular pages at build time and letting less common pages generate on-demand with dynamicParams = true. Monitor your build times and adjust accordingly.
Security consideration: Never cache user-specific data indefinitely. Dynamic routes accessing authentication state, user preferences, or personalized content should use dynamic = 'force-dynamic' or appropriate cache: 'no-store' fetch options.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite