[Next.js 16] use cache works locally but not on Vercel Production for dynamic route #88038
-
SummaryEnvironment
IssueThe "use cache" directive works correctly when building and running locally, but when deployed on Vercel it always invokes the function instead of returning cached values, even when called with the same parameters. what i wanna doI want to make the page stream using PPR, and I want to stream it immediately using a cached component. However, when I deploy to Vercel, it doesn’t work and the API keeps being called repeatedly. Local Production Build Result
Code where use "use cache"// app/category/[category]/[subCategory]/page.tsx
import { cacheLife, cacheTag } from "next/cache";
import { HydrationBoundary, QueryClient, dehydrate } from "@tanstack/react-query";
// Page
export default async function Page({ params }: PageProps) {
return (
<Suspense>
{params.then(({ subCategory }) => (
<CachedComponent encodedSubCategory={subCategory} />
))}
</Suspense>
);
}
// Cached Component
const CachedComponent = async ({ encodedSubCategory }: { encodedSubCategory: string }) => {
"use cache";
cacheLife("max");
const [subCategory, dehydratedState] = await getCachedPageData(encodedSubCategory);
return (
<HydrationBoundary state={dehydratedState}>
<ArticleListContainer category={subCategory} />
</HydrationBoundary>
);
};
// Cached Data
const getCachedPageData = async (encodedSubCategory: string) => {
"use cache";
const subCategory = decodeURIComponent(encodedSubCategory);
cacheLife("max");
cacheTag(`category-${subCategory}-page`); // tag: ["category-Javascript-page"]
const dehydratedState = await prefetchCategoryArticles(subCategory, 0, 12);
return [subCategory, dehydratedState] as const;
};
// <-- Don't need to Read-->
const prefetchCategoryArticles = async (
subCategory: string,
cursor: number,
limit: number
) => {
"use cache";
cacheLife("max");
const queryClient = new QueryClient();
await queryClient.prefetchInfiniteQuery({
queryKey: ["articles", "category", subCategory, limit.toString()],
queryFn: async ({ pageParam }) => {
// Fetch from backend API
const { data } = await getArticleByCategory(subCategory, pageParam, limit);
return data;
},
initialPageParam: cursor,
});
return dehydrate(queryClient); // maybe serializable
};Expected BehaviorWhen accessing the same category multiple times (e.g., /category/Frontend/React or /category/Frontend/Angular), the cached function should return the cached dehydratedState instead of being re-invoked. Actual BehaviorLocal Production Build (pnpm build && pnpm start)
Vercel Production Deployment
What I've Confirmed
Questions
Additional informationNo response ExampleNo response |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 2 replies
-
Beta Was this translation helpful? Give feedback.
-
|
@YoonDongGeun The correct workaround (production-safe) : import { unstable_cache } from "next/cache";
export const getCategoryData = unstable_cache(
async (subCategory: string, cursor: number, limit: number) => {
return await fetchCategoryFromBackend(subCategory, cursor, limit);
},
(subCategory, cursor, limit) => [
`category:${subCategory}`,
`cursor:${cursor}`,
`limit:${limit}`,
],
{
revalidate: 60 * 60 * 24 * 7, // 7 days
tags: (subCategory) => [`category-${subCategory}`],
}
);Then in your page: const data = await getCategoryData(subCategory, cursor, limit); |
Beta Was this translation helpful? Give feedback.
-
|
Use fetch with next cache options : await fetch(url, {
next: {
revalidate: 86400,
tags: [`category-${subCategory}`],
},
}); |
Beta Was this translation helpful? Give feedback.







@YoonDongGeun
You cannot truly fix this right now. This is a known limitation / bug in Next.js 16 on Vercel production where use cache does not work reliably with dynamic routes.
It works locally because local Node has a stable process and memory. Vercel production does not.
So the only correct move today is to work around it, not to fight it.
The correct workaround (production-safe) :