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 72d44c8407c3..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: false,
},
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 5f1cf1f12fa7..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 (default)', () => {
- 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 5a877d2dbfab..000000000000
--- a/test/development/dev-cache-control-no-cache-disabled/next.config.js
+++ /dev/null
@@ -1,2 +0,0 @@
-/** @type {import('next').NextConfig} */
-module.exports = {}
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/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/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/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
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 = [
diff --git a/test/rspack-dev-tests-manifest.json b/test/rspack-dev-tests-manifest.json
index 1910ec5dc7f1..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 (default) should use no-store for app router by default",
- "experimental.devCacheControlNoCache disabled (default) 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": [],