From 7ad483baacf4a0853bdec0a699cbe26235b88c34 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 17 Mar 2026 12:54:56 +0000 Subject: [PATCH 1/4] Change devCacheControlNoCache default from false to true Makes no-cache, must-revalidate the default dev Cache-Control header. The disabled test fixture now opts out explicitly with devCacheControlNoCache: false. Co-Authored-By: Claude --- packages/next/src/server/config-shared.ts | 2 +- .../dev-cache-control-no-cache-disabled.test.ts | 2 +- .../dev-cache-control-no-cache-disabled/next.config.js | 6 +++++- test/development/dev-cache-control-no-cache/next.config.js | 6 +----- test/rspack-dev-tests-manifest.json | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index 72d44c8407c3..5f6627f527ab 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -1812,7 +1812,7 @@ export const defaultConfig = Object.freeze({ turbopackFileSystemCacheForBuild: false, turbopackInferModuleSideEffects: true, turbopackPluginRuntimeStrategy: 'childProcesses', - devCacheControlNoCache: false, + devCacheControlNoCache: true, }, htmlLimitedBots: undefined, bundlePagesRouterDependencies: false, diff --git a/test/development/dev-cache-control-no-cache-disabled/dev-cache-control-no-cache-disabled.test.ts b/test/development/dev-cache-control-no-cache-disabled/dev-cache-control-no-cache-disabled.test.ts index 5f1cf1f12fa7..467639c384da 100644 --- a/test/development/dev-cache-control-no-cache-disabled/dev-cache-control-no-cache-disabled.test.ts +++ b/test/development/dev-cache-control-no-cache-disabled/dev-cache-control-no-cache-disabled.test.ts @@ -1,6 +1,6 @@ import { nextTestSetup } from 'e2e-utils' -describe('experimental.devCacheControlNoCache disabled (default)', () => { +describe('experimental.devCacheControlNoCache disabled (explicit opt-out)', () => { const { next } = nextTestSetup({ files: __dirname, }) diff --git a/test/development/dev-cache-control-no-cache-disabled/next.config.js b/test/development/dev-cache-control-no-cache-disabled/next.config.js index 5a877d2dbfab..7c6909d2b653 100644 --- a/test/development/dev-cache-control-no-cache-disabled/next.config.js +++ b/test/development/dev-cache-control-no-cache-disabled/next.config.js @@ -1,2 +1,6 @@ /** @type {import('next').NextConfig} */ -module.exports = {} +module.exports = { + experimental: { + devCacheControlNoCache: false, + }, +} diff --git a/test/development/dev-cache-control-no-cache/next.config.js b/test/development/dev-cache-control-no-cache/next.config.js index 0f939a1f9b51..5a877d2dbfab 100644 --- a/test/development/dev-cache-control-no-cache/next.config.js +++ b/test/development/dev-cache-control-no-cache/next.config.js @@ -1,6 +1,2 @@ /** @type {import('next').NextConfig} */ -module.exports = { - experimental: { - devCacheControlNoCache: true, - }, -} +module.exports = {} diff --git a/test/rspack-dev-tests-manifest.json b/test/rspack-dev-tests-manifest.json index 1910ec5dc7f1..94acfa96aaf6 100644 --- a/test/rspack-dev-tests-manifest.json +++ b/test/rspack-dev-tests-manifest.json @@ -1995,8 +1995,8 @@ }, "test/development/dev-cache-control-no-cache-disabled/dev-cache-control-no-cache-disabled.test.ts": { "passed": [ - "experimental.devCacheControlNoCache disabled (default) should use no-store for app router by default", - "experimental.devCacheControlNoCache disabled (default) should use no-store for pages router by default" + "experimental.devCacheControlNoCache disabled (explicit opt-out) should use no-store for app router by default", + "experimental.devCacheControlNoCache disabled (explicit opt-out) should use no-store for pages router by default" ], "failed": [], "pending": [], From 5f787e3f6206e9bd66fbdadf1d1e5f4efd9f1529 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 17 Mar 2026 13:01:18 +0000 Subject: [PATCH 2/4] Remove devCacheControlNoCache experimental option The no-cache, must-revalidate behavior is now unconditional in dev. Removes the config field, schema entry, type, default, and all conditional branches. Deletes the disabled test suite and renames the remaining test to drop the experimental framing. Co-Authored-By: Claude --- packages/next/src/build/templates/app-page.ts | 7 +----- packages/next/src/server/base-server.ts | 7 +----- packages/next/src/server/config-schema.ts | 1 - packages/next/src/server/config-shared.ts | 15 ------------ packages/next/src/server/lib/router-server.ts | 7 +----- .../route-modules/pages/pages-handler.ts | 7 +----- .../app/app-route/page.js | 3 --- .../app/layout.js | 7 ------ ...ev-cache-control-no-cache-disabled.test.ts | 17 ------------- .../next.config.js | 6 ----- .../pages/pages-route.js | 3 --- .../dev-cache-control-no-cache.test.ts | 24 +++++++++---------- test/rspack-dev-tests-manifest.json | 14 ++--------- 13 files changed, 17 insertions(+), 101 deletions(-) delete mode 100644 test/development/dev-cache-control-no-cache-disabled/app/app-route/page.js delete mode 100644 test/development/dev-cache-control-no-cache-disabled/app/layout.js delete mode 100644 test/development/dev-cache-control-no-cache-disabled/dev-cache-control-no-cache-disabled.test.ts delete mode 100644 test/development/dev-cache-control-no-cache-disabled/next.config.js delete mode 100644 test/development/dev-cache-control-no-cache-disabled/pages/pages-route.js diff --git a/packages/next/src/build/templates/app-page.ts b/packages/next/src/build/templates/app-page.ts index b95e44f1e703..260706d15c15 100644 --- a/packages/next/src/build/templates/app-page.ts +++ b/packages/next/src/build/templates/app-page.ts @@ -1389,12 +1389,7 @@ export async function handler( // In dev, we should not cache pages for any reason. if (routeModule.isDev) { - res.setHeader( - 'Cache-Control', - nextConfig.experimental.devCacheControlNoCache - ? 'no-cache, must-revalidate' - : 'no-store, must-revalidate' - ) + res.setHeader('Cache-Control', 'no-cache, must-revalidate') } if (!cacheEntry) { diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index cd49c0169995..6a314f107339 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -1803,12 +1803,7 @@ export default abstract class Server< // In dev, we should not cache pages for any reason. if (this.dev) { - res.setHeader( - 'Cache-Control', - this.nextConfig.experimental.devCacheControlNoCache - ? 'no-cache, must-revalidate' - : 'no-store, must-revalidate' - ) + res.setHeader('Cache-Control', 'no-cache, must-revalidate') cacheControl = undefined } diff --git a/packages/next/src/server/config-schema.ts b/packages/next/src/server/config-schema.ts index 57d06b2bddb1..191cee5c0e73 100644 --- a/packages/next/src/server/config-schema.ts +++ b/packages/next/src/server/config-schema.ts @@ -404,7 +404,6 @@ export const experimentalSchema = { hideLogsAfterAbort: z.boolean().optional(), runtimeServerDeploymentId: z.boolean().optional(), immutableAssetToken: z.string().optional(), - devCacheControlNoCache: z.boolean().optional(), deferredEntries: z.array(z.string()).optional(), onBeforeDeferredEntries: z.function().returns(z.promise(z.void())).optional(), reportSystemEnvInlining: z.enum(['warn', 'error']).optional(), diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index 5f6627f527ab..d143119f2140 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -1039,18 +1039,6 @@ export interface ExperimentalConfig { */ immutableAssetToken?: string - /** - * Use 'no-cache' instead of 'no-store' in the Cache-Control header for development. - * This allows conditional requests to the server, which can help with development - * workflows that benefit from caching validation. - * - * When enabled, the Cache-Control header changes from 'no-store, must-revalidate' - * to 'no-cache, must-revalidate'. - * - * @default false - */ - devCacheControlNoCache?: boolean - /** * An array of paths in app or pages directories that should wait to be processed * until all other entries have been processed. This is useful for deferring @@ -1812,7 +1800,6 @@ export const defaultConfig = Object.freeze({ turbopackFileSystemCacheForBuild: false, turbopackInferModuleSideEffects: true, turbopackPluginRuntimeStrategy: 'childProcesses', - devCacheControlNoCache: true, }, htmlLimitedBots: undefined, bundlePagesRouterDependencies: false, @@ -1911,7 +1898,6 @@ export interface NextConfigRuntime { | 'testProxy' | 'runtimeServerDeploymentId' | 'maxPostponedStateSize' - | 'devCacheControlNoCache' | 'cachedNavigations' | 'partialFallbacks' | 'exposeTestingApiInProductionBuild' @@ -1982,7 +1968,6 @@ export function getNextConfigRuntime( testProxy: ex.testProxy, runtimeServerDeploymentId: ex.runtimeServerDeploymentId, maxPostponedStateSize: ex.maxPostponedStateSize, - devCacheControlNoCache: ex.devCacheControlNoCache, cachedNavigations: ex.cachedNavigations, partialFallbacks: ex.partialFallbacks, exposeTestingApiInProductionBuild: ex.exposeTestingApiInProductionBuild, diff --git a/packages/next/src/server/lib/router-server.ts b/packages/next/src/server/lib/router-server.ts index 80f1fbe75756..f866b8f46323 100644 --- a/packages/next/src/server/lib/router-server.ts +++ b/packages/next/src/server/lib/router-server.ts @@ -507,12 +507,7 @@ export async function initialize(opts: { matchedOutput.type === 'nextStaticFolder' ) { if (opts.dev && !isNextFont(parsedUrl.pathname)) { - res.setHeader( - 'Cache-Control', - config.experimental.devCacheControlNoCache - ? 'no-cache, must-revalidate' - : 'no-store, must-revalidate' - ) + res.setHeader('Cache-Control', 'no-cache, must-revalidate') } else { res.setHeader( 'Cache-Control', diff --git a/packages/next/src/server/route-modules/pages/pages-handler.ts b/packages/next/src/server/route-modules/pages/pages-handler.ts index 37d66d8cf1ef..792d78eb02ad 100644 --- a/packages/next/src/server/route-modules/pages/pages-handler.ts +++ b/packages/next/src/server/route-modules/pages/pages-handler.ts @@ -706,12 +706,7 @@ export const getHandler = ({ // In dev, we should not cache pages for any reason. if (routeModule.isDev) { - res.setHeader( - 'Cache-Control', - nextConfig.experimental.devCacheControlNoCache - ? 'no-cache, must-revalidate' - : 'no-store, must-revalidate' - ) + res.setHeader('Cache-Control', 'no-cache, must-revalidate') } // Draft mode should never be cached diff --git a/test/development/dev-cache-control-no-cache-disabled/app/app-route/page.js b/test/development/dev-cache-control-no-cache-disabled/app/app-route/page.js deleted file mode 100644 index cabb5263b521..000000000000 --- a/test/development/dev-cache-control-no-cache-disabled/app/app-route/page.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function AppRoute() { - return
App Route
-} diff --git a/test/development/dev-cache-control-no-cache-disabled/app/layout.js b/test/development/dev-cache-control-no-cache-disabled/app/layout.js deleted file mode 100644 index 4ee00a218505..000000000000 --- a/test/development/dev-cache-control-no-cache-disabled/app/layout.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function RootLayout({ children }) { - return ( - - {children} - - ) -} diff --git a/test/development/dev-cache-control-no-cache-disabled/dev-cache-control-no-cache-disabled.test.ts b/test/development/dev-cache-control-no-cache-disabled/dev-cache-control-no-cache-disabled.test.ts deleted file mode 100644 index 467639c384da..000000000000 --- a/test/development/dev-cache-control-no-cache-disabled/dev-cache-control-no-cache-disabled.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { nextTestSetup } from 'e2e-utils' - -describe('experimental.devCacheControlNoCache disabled (explicit opt-out)', () => { - const { next } = nextTestSetup({ - files: __dirname, - }) - - it('should use no-store for pages router by default', async () => { - const res = await next.fetch('/pages-route') - expect(res.headers.get('Cache-Control')).toBe('no-store, must-revalidate') - }) - - it('should use no-store for app router by default', async () => { - const res = await next.fetch('/app-route') - expect(res.headers.get('Cache-Control')).toBe('no-store, must-revalidate') - }) -}) diff --git a/test/development/dev-cache-control-no-cache-disabled/next.config.js b/test/development/dev-cache-control-no-cache-disabled/next.config.js deleted file mode 100644 index 7c6909d2b653..000000000000 --- a/test/development/dev-cache-control-no-cache-disabled/next.config.js +++ /dev/null @@ -1,6 +0,0 @@ -/** @type {import('next').NextConfig} */ -module.exports = { - experimental: { - devCacheControlNoCache: false, - }, -} diff --git a/test/development/dev-cache-control-no-cache-disabled/pages/pages-route.js b/test/development/dev-cache-control-no-cache-disabled/pages/pages-route.js deleted file mode 100644 index 80120c33615c..000000000000 --- a/test/development/dev-cache-control-no-cache-disabled/pages/pages-route.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function PagesRoute() { - return
Pages Route
-} diff --git a/test/development/dev-cache-control-no-cache/dev-cache-control-no-cache.test.ts b/test/development/dev-cache-control-no-cache/dev-cache-control-no-cache.test.ts index edbe93714b89..2a38178d4344 100644 --- a/test/development/dev-cache-control-no-cache/dev-cache-control-no-cache.test.ts +++ b/test/development/dev-cache-control-no-cache/dev-cache-control-no-cache.test.ts @@ -1,19 +1,17 @@ import { nextTestSetup } from 'e2e-utils' -describe('experimental.devCacheControlNoCache', () => { - describe('when enabled', () => { - const { next } = nextTestSetup({ - files: __dirname, - }) +describe('dev Cache-Control header', () => { + const { next } = nextTestSetup({ + files: __dirname, + }) - it('should use no-cache instead of no-store for pages router', async () => { - const res = await next.fetch('/pages-route') - expect(res.headers.get('Cache-Control')).toBe('no-cache, must-revalidate') - }) + it('should use no-cache for pages router', async () => { + const res = await next.fetch('/pages-route') + expect(res.headers.get('Cache-Control')).toBe('no-cache, must-revalidate') + }) - it('should use no-cache instead of no-store for app router', async () => { - const res = await next.fetch('/app-route') - expect(res.headers.get('Cache-Control')).toBe('no-cache, must-revalidate') - }) + it('should use no-cache for app router', async () => { + const res = await next.fetch('/app-route') + expect(res.headers.get('Cache-Control')).toBe('no-cache, must-revalidate') }) }) diff --git a/test/rspack-dev-tests-manifest.json b/test/rspack-dev-tests-manifest.json index 94acfa96aaf6..48081cf71a88 100644 --- a/test/rspack-dev-tests-manifest.json +++ b/test/rspack-dev-tests-manifest.json @@ -1993,20 +1993,10 @@ "flakey": [], "runtimeError": false }, - "test/development/dev-cache-control-no-cache-disabled/dev-cache-control-no-cache-disabled.test.ts": { - "passed": [ - "experimental.devCacheControlNoCache disabled (explicit opt-out) should use no-store for app router by default", - "experimental.devCacheControlNoCache disabled (explicit opt-out) should use no-store for pages router by default" - ], - "failed": [], - "pending": [], - "flakey": [], - "runtimeError": false - }, "test/development/dev-cache-control-no-cache/dev-cache-control-no-cache.test.ts": { "passed": [ - "experimental.devCacheControlNoCache when enabled should use no-cache instead of no-store for app router", - "experimental.devCacheControlNoCache when enabled should use no-cache instead of no-store for pages router" + "dev Cache-Control header should use no-cache for app router", + "dev Cache-Control header should use no-cache for pages router" ], "failed": [], "pending": [], From 0ec864492a9de087fc354271b103a08a01e557c8 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 17 Mar 2026 13:53:25 +0000 Subject: [PATCH 3/4] Fix tests that hardcoded no-store dev cache-control expectation Update all tests to expect no-cache instead of no-store in dev mode, and fix fallback-prefetch to not treat 304 Not Modified as a network error. Co-Authored-By: Claude --- .../client-navigation/rendering.test.ts | 2 +- .../custom-cache-control.test.ts | 18 +++++++++--------- .../fallback-prefetch.test.ts | 4 +++- test/e2e/app-dir/metadata/metadata.test.ts | 6 +++--- test/e2e/prerender.test.ts | 2 +- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/test/development/pages-dir/client-navigation/rendering.test.ts b/test/development/pages-dir/client-navigation/rendering.test.ts index 17c5a5255323..e4bb383f4f95 100644 --- a/test/development/pages-dir/client-navigation/rendering.test.ts +++ b/test/development/pages-dir/client-navigation/rendering.test.ts @@ -396,7 +396,7 @@ describe('Client Navigation rendering', () => { responses.forEach((res) => { try { expect(res.headers.get('Cache-Control')).toBe( - 'no-store, must-revalidate' + 'no-cache, must-revalidate' ) } catch (err) { err.message = res.url + ' ' + err.message diff --git a/test/e2e/app-dir/custom-cache-control/custom-cache-control.test.ts b/test/e2e/app-dir/custom-cache-control/custom-cache-control.test.ts index ffe2610ccd03..121ecc0207f0 100644 --- a/test/e2e/app-dir/custom-cache-control/custom-cache-control.test.ts +++ b/test/e2e/app-dir/custom-cache-control/custom-cache-control.test.ts @@ -15,14 +15,14 @@ describe('custom-cache-control', () => { it('should have custom cache-control for app-ssg prerendered', async () => { const res = await next.fetch('/app-ssg/first') expect(res.headers.get('cache-control')).toBe( - isNextDev ? 'no-store, must-revalidate' : 's-maxage=30' + isNextDev ? 'no-cache, must-revalidate' : 's-maxage=30' ) }) it('should have custom cache-control for app-ssg lazy', async () => { const res = await next.fetch('/app-ssg/lazy') expect(res.headers.get('cache-control')).toBe( - isNextDev ? 'no-store, must-revalidate' : 's-maxage=31' + isNextDev ? 'no-cache, must-revalidate' : 's-maxage=31' ) }) ;(process.env.__NEXT_CACHE_COMPONENTS ? it.skip : it)( @@ -32,7 +32,7 @@ describe('custom-cache-control', () => { // eslint-disable-next-line jest/no-standalone-expect expect(res.headers.get('cache-control')).toBe( isNextDev - ? 'no-store, must-revalidate' + ? 'no-cache, must-revalidate' : 's-maxage=120, stale-while-revalidate=31535880' ) } @@ -41,28 +41,28 @@ describe('custom-cache-control', () => { it('should have custom cache-control for app-ssr', async () => { const res = await next.fetch('/app-ssr') expect(res.headers.get('cache-control')).toBe( - isNextDev ? 'no-store, must-revalidate' : 's-maxage=32' + isNextDev ? 'no-cache, must-revalidate' : 's-maxage=32' ) }) it('should have custom cache-control for auto static page', async () => { const res = await next.fetch('/pages-auto-static') expect(res.headers.get('cache-control')).toBe( - isNextDev ? 'no-store, must-revalidate' : 's-maxage=33' + isNextDev ? 'no-cache, must-revalidate' : 's-maxage=33' ) }) it('should have custom cache-control for pages-ssg prerendered', async () => { const res = await next.fetch('/pages-ssg/first') expect(res.headers.get('cache-control')).toBe( - isNextDev ? 'no-store, must-revalidate' : 's-maxage=34' + isNextDev ? 'no-cache, must-revalidate' : 's-maxage=34' ) }) it('should have custom cache-control for pages-ssg lazy', async () => { const res = await next.fetch('/pages-ssg/lazy') expect(res.headers.get('cache-control')).toBe( - isNextDev ? 'no-store, must-revalidate' : 's-maxage=35' + isNextDev ? 'no-cache, must-revalidate' : 's-maxage=35' ) }) @@ -70,7 +70,7 @@ describe('custom-cache-control', () => { const res = await next.fetch('/pages-ssg/another') expect(res.headers.get('cache-control')).toBe( isNextDev - ? 'no-store, must-revalidate' + ? 'no-cache, must-revalidate' : 's-maxage=120, stale-while-revalidate=31535880' ) }) @@ -78,7 +78,7 @@ describe('custom-cache-control', () => { it('should have default cache-control for pages-ssr', async () => { const res = await next.fetch('/pages-ssr') expect(res.headers.get('cache-control')).toBe( - isNextDev ? 'no-store, must-revalidate' : 's-maxage=36' + isNextDev ? 'no-cache, must-revalidate' : 's-maxage=36' ) }) }) diff --git a/test/e2e/app-dir/fallback-prefetch/fallback-prefetch.test.ts b/test/e2e/app-dir/fallback-prefetch/fallback-prefetch.test.ts index ec10619bef1c..34e67c8b17a3 100644 --- a/test/e2e/app-dir/fallback-prefetch/fallback-prefetch.test.ts +++ b/test/e2e/app-dir/fallback-prefetch/fallback-prefetch.test.ts @@ -10,7 +10,9 @@ describe('fallback-prefetch', () => { const browser = await next.browser('/', { beforePageLoad: (page) => { page.on('response', (response) => { - if (!response.ok()) { + // 304 Not Modified is a valid revalidation response (from no-cache), + // not a network error + if (!response.ok() && response.status() !== 304) { hasNetworkError = true } }) diff --git a/test/e2e/app-dir/metadata/metadata.test.ts b/test/e2e/app-dir/metadata/metadata.test.ts index 97d9014a3122..17f0a6186913 100644 --- a/test/e2e/app-dir/metadata/metadata.test.ts +++ b/test/e2e/app-dir/metadata/metadata.test.ts @@ -691,7 +691,7 @@ describe('app dir - metadata', () => { expect(res.headers.get('content-type')).toBe('image/x-icon') expect(res.headers.get('cache-control')).toBe( isNextDev - ? 'no-store, must-revalidate' + ? 'no-cache, must-revalidate' : 'public, max-age=0, must-revalidate' ) }) @@ -706,14 +706,14 @@ describe('app dir - metadata', () => { expect(resAppleIcon.headers.get('content-type')).toBe('image/png') expect(resAppleIcon.headers.get('cache-control')).toBe( isNextDev - ? 'no-store, must-revalidate' + ? 'no-cache, must-revalidate' : 'public, max-age=0, must-revalidate' ) expect(resIcon.status).toBe(200) expect(resIcon.headers.get('content-type')).toBe('image/png') expect(resIcon.headers.get('cache-control')).toBe( isNextDev - ? 'no-store, must-revalidate' + ? 'no-cache, must-revalidate' : 'public, max-age=0, must-revalidate' ) }) diff --git a/test/e2e/prerender.test.ts b/test/e2e/prerender.test.ts index c045f54cf4d3..1a280d6e3372 100644 --- a/test/e2e/prerender.test.ts +++ b/test/e2e/prerender.test.ts @@ -91,7 +91,7 @@ describe('Prerender', () => { } function isCachingHeader(cacheControl) { - return !cacheControl || !/no-store/.test(cacheControl) + return !cacheControl || !/no-store|no-cache/.test(cacheControl) } const allowHeader = [ From b7b326452d73157f4a104730523ddc60b5cab541 Mon Sep 17 00:00:00 2001 From: Vercel Date: Tue, 17 Mar 2026 14:30:29 +0000 Subject: [PATCH 4/4] Fix: Test at ppr-full.test.ts:195 still expects the old `no-store, must-revalidate` Cache-Control header, causing test failure in dev mode. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit fixes the issue reported at test/e2e/app-dir/ppr-full/ppr-full.test.ts:195 **Bug analysis:** The PR removed the `experimental.devCacheControlNoCache` config option and hard-coded the dev server Cache-Control header to `no-cache, must-revalidate` (changed from the old default of `no-store, must-revalidate`). This change was applied across three server files: - `packages/next/src/server/base-server.ts` - `packages/next/src/server/route-modules/pages/pages-handler.ts` - `packages/next/src/server/lib/router-server.ts` A follow-up commit (716520a) updated numerous tests to expect the new `no-cache, must-revalidate` header value (visible in files like `custom-cache-control.test.ts`, `metadata.test.ts`, `dev-cache-control-no-cache.test.ts`, and `rendering.test.ts`). However, `test/e2e/app-dir/ppr-full/ppr-full.test.ts` at line 195 was missed — it's the **only** remaining instance of `no-store, must-revalidate` across the entire `test/` directory. When the PPR full test suite runs in dev mode (`isNextDev === true`), it hits this assertion which expects the old `no-store, must-revalidate` header but the dev server now returns `no-cache, must-revalidate`, causing the test to fail. **Fix:** Changed line 195 from `expect(cacheControl).toEqual('no-store, must-revalidate')` to `expect(cacheControl).toEqual('no-cache, must-revalidate')` to match the new dev server behavior. Co-authored-by: Vercel Co-authored-by: sokra --- test/e2e/app-dir/ppr-full/ppr-full.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/app-dir/ppr-full/ppr-full.test.ts b/test/e2e/app-dir/ppr-full/ppr-full.test.ts index 7e76d4abab43..0d5d305d78ba 100644 --- a/test/e2e/app-dir/ppr-full/ppr-full.test.ts +++ b/test/e2e/app-dir/ppr-full/ppr-full.test.ts @@ -192,7 +192,7 @@ describe.skip('ppr-full', () => { if (isNextDeploy) { expect(cacheControl).toEqual('public, max-age=0, must-revalidate') } else if (isNextDev) { - expect(cacheControl).toEqual('no-store, must-revalidate') + expect(cacheControl).toEqual('no-cache, must-revalidate') } else if (dynamic === false || dynamic === 'force-static') { expect(cacheControl).toEqual( revalidate === undefined