How do you set custom cache control headers in the response for pages in app router?
Unanswered
Rhinelander posted this in #help-forum
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
RhinelanderOP
Eg.
Looks like you can't set them in next.config.js for pages: https://nextjs.org/docs/app/api-reference/next-config-js/headers#cache-control
You can't set them in the pages either in the response. How do you achieve this? I cannot believe we cannot set custom cache control for pages in app router. This is possible in pages router. I don't deploy to Vercel. I deploy to custom infra on AWS. I want to be able to set the http standard cache control headers on my page responses.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
// Page A - cache only on CDN
"Cache-Control": "public, max-age=0, s-maxage=60, must-revalidate"
// Page B - don't cache anywhere
"Cache-Control": "no-cache, no-store, max-age=0, must-revalidate"
// Page C - cache on client and CDN
"Cache-Control": "public, max-age=60, s-maxage=60, must-revalidate"
Looks like you can't set them in next.config.js for pages: https://nextjs.org/docs/app/api-reference/next-config-js/headers#cache-control
You can't set them in the pages either in the response. How do you achieve this? I cannot believe we cannot set custom cache control for pages in app router. This is possible in pages router. I don't deploy to Vercel. I deploy to custom infra on AWS. I want to be able to set the http standard cache control headers on my page responses.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
16 Replies
![Avatar](https://cdn.discordapp.com/avatars/301376057326567425/788b75eb8862277af3d31d317ada783f.webp?size=256)
B33fb0n3
you may looking for this, don't you?
https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic
https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
RhinelanderOP
That doesn't let you set fine grain cache control headers like the ones I shared in my post above
![Avatar](https://cdn.discordapp.com/avatars/301376057326567425/788b75eb8862277af3d31d317ada783f.webp?size=256)
B33fb0n3
you can't directly overwrite or fine grain the cache control header. However you can use [route segment options](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config) to say how nextjs should handle the caching and revalidations
![Avatar](https://cdn.discordapp.com/avatars/1070665442298966106/ce262b83ad4eeb2ec98efa074aefe4cb.webp?size=256)
Luke
I believe this can be controlled here:
If you're after controlling it on the page, consider separating out your data into something you can fetch from a route handler, where you can then control the caching more granularly.
Combined with react suspense, you can create an incredibly professional looking user experience
https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#opting-out-of-data-caching
If you're after controlling it on the page, consider separating out your data into something you can fetch from a route handler, where you can then control the caching more granularly.
Combined with react suspense, you can create an incredibly professional looking user experience
https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#opting-out-of-data-caching
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
RhinelanderOP
I don't want to cache the data. I've forced the fetch handlers to use
no-store
. I want to be able to set custom cache control headers in the page response so the pages I specify s-maxage
for gets cached on the CDN in front of my server instance for the time I specify.![Avatar](https://cdn.discordapp.com/avatars/1070665442298966106/ce262b83ad4eeb2ec98efa074aefe4cb.webp?size=256)
Luke
I don't think either of you read my reply correctly :/
![Avatar](https://cdn.discordapp.com/avatars/1070665442298966106/ce262b83ad4eeb2ec98efa074aefe4cb.webp?size=256)
Luke
So either you DO want route segment options as @B33fb0n3 suggested, or you want to follow the new model for granular caching, where your page relies on uncached fetches.
So basically, the new way of doing it is to use a fetch for your data, and never cache for your fetch.
The new model in the app directory favors granular caching control at the fetch request level over the binary all-or-nothing model of getServerSideProps and getStaticProps at the page-level in the pages directory. Thedynamic
option is a way to opt back in to the previous model as a convenience and provides a simpler migration path.
'force-dynamic'
: Force [dynamic rendering](https://nextjs.org/docs/app/building-your-application/rendering/server-components#dynamic-rendering), which will result in routes being rendered for each user at request time. This option is equivalent to getServerSideProps() in the pages directory.
So basically, the new way of doing it is to use a fetch for your data, and never cache for your fetch.
The problem will only really come if you use something like fastly or cloudfront, which are harder to control without headers
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
RhinelanderOP
I'm familiar with how the app router works. I'm not interested in caching the data. I want to cache the entire page. I want to render the entire page request time and return cache-control headers in the response so the page gets cached at the CDN in front of the server. The CDN will return from the cache and avoid origin requests as long as the cache is fresh. This was possible with pages router. I can't seem to find a way to do this with app router.
force-dynamic
doesn't let you specify cache control headers. if you want to cache the page in the private cache (browser) or the public cache (CDN), you need to set the cache-control header. If you want to cache in the browser for 1 minute and in the CDN for 1 day, you will need to use the cache control header.![Avatar](https://cdn.discordapp.com/avatars/1070665442298966106/ce262b83ad4eeb2ec98efa074aefe4cb.webp?size=256)
Luke
☝🏻 with more context, you can see I agree
I do believe that
Cache-control
are written by the route segment configCache-control: s-maxage=60, stale-while-revalidate
will look like this:
export const dynamic = 'force-static';
export const revalidate = 60;
but it doesn't appear to go far enough to support exactly what you want
only thing I can think of, is to use middleware for those routes. i am just looking into multiple middleware for my own purposes
export function middleware(request: NextRequest) {
const response = NextResponse.next();
response.headers.set('Cache-Control', 'public, max-age=0, s-maxage=60, must-revalidate');
return response;
}
export const config = {
matcher: ['/route-a'],
};
![Avatar](https://cdn.discordapp.com/embed/avatars/2.png)
RhinelanderOP
I will need to try the middleware approach. If the framework overrides the cache control set in next.config.js it probably will override the cache control set in the middleware as well (i'm just guessing here). But if the cache-control headers set in the middleware are retained, perhaps path matching the request and setting custom cache control headers based on the path might be the way to go.