expireTime
Sets the stale-while-revalidate window CDNs receive in Cache-Control for ISR pages.
expireTime?: numberParameters
| Parameter | Type | Description |
|---|---|---|
$expireTimeoptional | number | Custom `stale-while-revalidate` expire time in seconds for CDNs to consume in the `Cache-Control` header for ISR enabled pages. |
expireTime changes the stale-while-revalidate figure Next.js writes into the Cache-Control header for ISR pages. It does not change when Next.js regenerates a page — your route's revalidate period still does that. It changes how long a shared cache in front of your app may keep serving the old copy while the new one is fetched.
How the number is derived
The header is computed per route from both values: the revalidate period becomes s-maxage, and stale-while-revalidate becomes the expire time minus that period. With a 15-minute revalidate and expireTime: 3600, Next.js sends:
Cache-Control: s-maxage=900, stale-while-revalidate=2700
When to reach for it
Raise it when your origin is expensive or occasionally slow and you would rather a CDN serve a slightly old page than queue requests behind a regeneration. Lower it when stale content is a correctness problem — pricing, stock levels, anything legally sensitive.
What trips people up
- It is a global default, not a per-route knob. Routes differ only through their own revalidate periods.
- Set it below a route's revalidate period and the subtraction leaves no useful stale window at all.
- It is only a header. A CDN that ignores
stale-while-revalidateignores this.
Example
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
// one hour in seconds
expireTime: 3600,
}
export default nextConfigWhen to use it
- Let a CDN keep serving a cached product page while regeneration runs against a slow origin.
- Shorten the stale window on pages where showing outdated content is a real problem.
- Line the header up with an edge cache's own stale-while-revalidate policy.
- Reduce origin load spikes when many revalidations expire at the same moment.
Frequently asked questions
What Cache-Control header does expireTime produce?
Next.js sends `s-maxage=<revalidate>, stale-while-revalidate=<expireTime - revalidate>` for ISR pages. The docs' example: with a 15-minute revalidate and expireTime of one hour, the header is `s-maxage=900, stale-while-revalidate=2700`, so the page can stay stale for 15 minutes less than the configured expire time.
Does expireTime change how often my page regenerates?
No. Regeneration is still driven by the route's revalidate period; expireTime only sets how long shared caches such as CDNs may keep serving the previous response while revalidation happens. Change the route's revalidate export to change regeneration frequency.
Can I set expireTime per route?
No — it is a single global value in next.config.ts. Per-route variation comes from each route's own revalidate period, which is subtracted from expireTime to produce that route's stale-while-revalidate window.
More examples
Reading the header the config produces
The two numbers combine per route. s-maxage is the route's own revalidate period of 900 seconds; stale-while-revalidate is 3600 - 900 = 2700, so the page may be served stale for 45 minutes past the point it went stale. Change either value and the header changes: a route with revalidate = 60 under the same config would get s-maxage=60, stale-while-revalidate=3540.
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
expireTime: 3600, // one hour
}
export default nextConfig
// app/blog/[slug]/page.tsx
export const revalidate = 900 // fifteen minutes
export default async function Page(props: PageProps<'/blog/[slug]'>) {
const { slug } = await props.params
return <h1>{slug}</h1>
}
// Response header for this route:
// Cache-Control: s-maxage=900, stale-while-revalidate=2700A short window where staleness is costly
Suitable for a catalogue where prices or stock counts must not linger. The trap is the subtraction: a route with `export const revalidate = 300` under this config leaves no stale window at all, and one with revalidate = 600 exceeds the expire time entirely. Keep expireTime comfortably above the longest revalidate period in the app, or the setting quietly does nothing useful.
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
// five minutes in seconds
expireTime: 300,
}
export default nextConfigEnvironment-dependent expire time
Production gets a generous 24-hour stale window that shields the origin from traffic spikes, while preview deployments get a 60-second one so reviewers see near-current content. Because next.config.ts is evaluated at build and server start, the branch is resolved once per deployment rather than per request — there is no way to vary this per visitor.
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
expireTime: process.env.VERCEL_ENV === 'production' ? 86_400 : 60,
}
export default nextConfig
Discussion