Upgrade to Next.js 16 cache components with canary build#184
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-authored-by: rauchg <13041+rauchg@users.noreply.github.com>
Co-authored-by: rauchg <13041+rauchg@users.noreply.github.com>
…ation Co-authored-by: rauchg <13041+rauchg@users.noreply.github.com>
| @@ -1,5 +1,3 @@ | |||
| export const revalidate = 300; | |||
There was a problem hiding this comment.
The OG image route handler has lost its caching mechanism. The export const revalidate = 300; was removed without being replaced with an equivalent caching directive, which means this route will not revalidate cached content or be cached at all.
View Details
📝 Patch Details
diff --git a/app/(post)/og/[id]/route.tsx b/app/(post)/og/[id]/route.tsx
index b8e1521..062e987 100644
--- a/app/(post)/og/[id]/route.tsx
+++ b/app/(post)/og/[id]/route.tsx
@@ -103,3 +103,8 @@ export async function GET(_req: Request, props) {
function font(fontFamily: string) {
return { fontFamily };
}
+
+// Cache the OG image generation for 300 seconds (ISR)
+GET.cacheLife = {
+ revalidate: 300,
+};
diff --git a/app/about/opengraph-image/route.tsx b/app/about/opengraph-image/route.tsx
index 52a2991..7f7b787 100644
--- a/app/about/opengraph-image/route.tsx
+++ b/app/about/opengraph-image/route.tsx
@@ -100,3 +100,8 @@ function toArrayBuffer(buffer) {
buffer.byteOffset + buffer.byteLength
);
}
+
+// Cache the OG image generation for 300 seconds (ISR)
+GET.cacheLife = {
+ revalidate: 300,
+};
diff --git a/app/api/posts/route.ts b/app/api/posts/route.ts
index 3b23373..3f143ae 100644
--- a/app/api/posts/route.ts
+++ b/app/api/posts/route.ts
@@ -1,6 +1,11 @@
-import { NextResponse } from "next/server";
-import { getPosts } from "../../get-posts";
+import { getPosts } from "@/app/get-posts";
export async function GET() {
- return NextResponse.json(await getPosts());
+ const posts = await getPosts();
+ return Response.json(posts);
}
+
+// Cache the posts API response for 300 seconds (ISR)
+GET.cacheLife = {
+ revalidate: 300,
+};
diff --git a/app/atom/route.ts b/app/atom/route.ts
index 6fe568c..7a332bc 100644
--- a/app/atom/route.ts
+++ b/app/atom/route.ts
@@ -35,3 +35,8 @@ export async function GET() {
}
);
}
+
+// Cache the atom feed for 300 seconds (ISR)
+GET.cacheLife = {
+ revalidate: 300,
+};
diff --git a/app/opengraph-image/route.tsx b/app/opengraph-image/route.tsx
index eccdff9..85235c7 100644
--- a/app/opengraph-image/route.tsx
+++ b/app/opengraph-image/route.tsx
@@ -80,3 +80,8 @@ function getYear(date: string) {
function font(fontFamily: string) {
return { fontFamily };
}
+
+// Cache the OG image generation for 300 seconds (ISR)
+GET.cacheLife = {
+ revalidate: 300,
+};
Analysis
Missing ISR cache configuration in route handlers after Next.js 16 upgrade
What fails: Route handlers for OG image generation, Atom feed, and Posts API lost their incremental static regeneration (ISR) configuration when caching was upgraded to use the "use cache" directive. Without explicit caching config on the route handlers themselves, responses are not revalidated and serve stale content indefinitely.
Affected routes:
app/(post)/og/[id]/route.tsx(dynamic OG images)app/opengraph-image/route.tsx(homepage OG image)app/about/opengraph-image/route.tsx(about page OG image)app/atom/route.ts(Atom feed)app/api/posts/route.ts(Posts API endpoint)
How to reproduce:
- Deploy the site without this fix
- Request an OG image:
/og/[post-id] - Update a blog post title in Redis or add a new post
- Request the same OG image again
- Old title/data is served due to missing revalidation
What happened: Response is cached indefinitely with no revalidation
Expected: Response revalidates every 300 seconds to reflect current data
Root cause: Commit a19b93d ("Upgrade to cache components with Next.js canary") removed export const revalidate = 300 from route handlers but did not add equivalent ISR configuration. While getPosts() function has "use cache" with .cacheLife for data-level caching, route handlers need their own caching directives for the HTTP response cache to revalidate per Next.js caching documentation.
Fix: Added GET.cacheLife = { revalidate: 300 } to all affected route handlers to restore the 300-second ISR revalidation pattern using the modern Next.js 16 caching model.
| @@ -1,5 +1,3 @@ | |||
| export const revalidate = 300; | |||
There was a problem hiding this comment.
The OG image route handler no longer has any caching mechanism, causing it to be rendered on every request instead of being cached.
View Details
📝 Patch Details
diff --git a/app/(post)/og/[id]/route.tsx b/app/(post)/og/[id]/route.tsx
index b8e1521..92a8a5d 100644
--- a/app/(post)/og/[id]/route.tsx
+++ b/app/(post)/og/[id]/route.tsx
@@ -1,3 +1,5 @@
+export const revalidate = 300;
+
import { ImageResponse } from "next/og";
import { getPosts } from "@/app/get-posts";
import { readFileSync } from "fs";
diff --git a/app/about/opengraph-image/route.tsx b/app/about/opengraph-image/route.tsx
index 52a2991..d62ff78 100644
--- a/app/about/opengraph-image/route.tsx
+++ b/app/about/opengraph-image/route.tsx
@@ -1,3 +1,5 @@
+export const revalidate = 300;
+
import { ImageResponse } from "next/og";
import { getPosts } from "@/app/get-posts";
import { readFileSync } from "fs";
diff --git a/app/opengraph-image/route.tsx b/app/opengraph-image/route.tsx
index eccdff9..b4829d4 100644
--- a/app/opengraph-image/route.tsx
+++ b/app/opengraph-image/route.tsx
@@ -1,3 +1,5 @@
+export const revalidate = 300;
+
import { ImageResponse } from "next/og";
import { getPosts } from "@/app/get-posts";
import { readFileSync } from "fs";
Analysis
OG image route handlers missing caching configuration
What fails: The home page, about page, and post-specific OG image route handlers (app/opengraph-image/route.tsx, app/about/opengraph-image/route.tsx, and app/(post)/og/[id]/route.tsx) execute on every request instead of being cached via ISR, making them inefficient for frequently accessed resources.
How to reproduce:
In Next.js 16+, GET route handlers are dynamic by default and execute on every request unless explicitly configured with export const revalidate = X. This is documented in the Next.js route handler documentation which states: "The default caching for GET handlers was changed from static to dynamic" and "GET handlers now execute on every request by default unless you explicitly configure caching."
The route handlers call getPosts() which has the "use cache" directive, but this caches only the function result, not the route handler's response. Each request still triggers the route handler execution.
Result: Every single request regenerates the OG image instead of reusing the cached version for 300 seconds.
Expected: OG images should be generated once, then revalidated every 300 seconds using ISR (Incremental Static Regeneration) as they were before the upgrade to cache components.
Why this happened: Commit a19b93d "Upgrade to cache components with Next.js canary" removed export const revalidate = 300 from these route handlers as part of migrating to the new "use cache" directive pattern. However, function-level caching via "use cache" does not substitute for route handler caching configuration. Per Next.js documentation, route handlers require their own caching configuration and do not inherit caching from functions they call.
Fix: Add export const revalidate = 300; at the top of these three route handler files to restore ISR caching behavior.
Migrates from page-level
revalidateexports to Next.js 16's function-level"use cache"directive for granular cache control.Package upgrades
16.0.0-beta.0→canary(16.0.1-canary.6)cacheComponents: truein next.config.jsCache component implementation
Before
After
Changes
getPosts(): cached with 300s revalidation and "posts" taggetAndCacheTweet(): cached with 300s revalidation and dynamictweet-${id}tagsrevalidateexports (now handled at function level)display: swap)Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
fonts.googleapis.com/usr/local/bin/node /home/REDACTED/work/blog/blog/node_modules/next/dist/compiled/jest-worker/processChild.js(dns block)global-apt-bear-30602.upstash.io/usr/local/bin/node /home/REDACTED/work/blog/blog/node_modules/.pnpm/next@16.0.1-canary.6_react-dom@19.2.0_react@19.2.0__react@19.2.0/node_modules/next/dist/compiled/jest-worker/processChild.js(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.