Why does a vanilla Drupal 8 site add cache-control: must-revalidate, no-cache, private to all the pages?

A Drupal 7 site adds cache-control: must-revalidate, no-cache.

Is that addition of private for Drupal 8 somehow configurable? I'd like to not have it there.

It turns out that this response header in Drupal 8 is sent when system.performance:cache.page.max_age is set to 0. Setting it to anything greater than 0 (e.g 123) gives me max-age=123, public. The question still remains: Is there a way to get must-revalidate, no-cache?

The reason I want must-revalidate, no-cache without private is that I want browsers to always make requests for pages, and my cache server (fastly) to cache the content. Having private in the response headers bypasses fastly as per their documentation: https://docs.fastly.com/en/guides/cache-control-tutorial#do-not-cache

  • 1
    I think you can use the drupal.org/project/http_response_headers module to change the header.
    – user72672
    Nov 13, 2019 at 9:56
  • 1
    Drupal doesn't respond with this header for all pages, only for logged-in users. You can specify different headers in a controller or change the headers of the response before it is delivered, see drupal.stackexchange.com/a/201297/47547
    – 4uk4
    Nov 13, 2019 at 10:20
  • @4k4 I do not confirm. I've tested a dozen of Drupal 7 and 8 sites via curl -I on their frontpage. Doing that way means that the request/response doesn't involve a logged in user.
    – cherouvim
    Nov 13, 2019 at 10:26
  • I get via curl Cache-Control: max-age=x, public, where x is the configured max-age.
    – 4uk4
    Nov 13, 2019 at 10:30
  • 1
    Have you tried the D7/D8 test on the same server? As there's lots of reasons for different headers include your servers configuration. E.g. I can see a hosting provider I use adds this tag by default
    – Leigh
    Nov 13, 2019 at 10:43

1 Answer 1


This is caused by symfony. private is added via vendor/symfony/http-foundation/ResponseHeaderBag.php and as far as I understand it's not possible to not have it when system.performance:cache.page.max_age is set to 0:

protected function computeCacheControlValue() {
  // ...
  if (!isset($this->cacheControl['s-maxage'])) {
    return $header.', private';

Since I don't want to hack symfony, I can remove private via apache mod_header:

Header edit Cache-Control "(, )?private" ""
  • As commented below the question these defaults are only applied if the controller or a response event subscriber doesn't set cache headers.
    – 4uk4
    Nov 13, 2019 at 12:24
  • My question regards why this has changed from D7 to D8 and how I can remove it.
    – cherouvim
    Nov 13, 2019 at 12:27
  • My comment is because you've said it's not possible, but it's the opposite, you have full control if you want.
    – 4uk4
    Nov 13, 2019 at 12:28
  • @4k4: I'm not following you. I don't want to hack symfony to change this behavior. Nor do I want to set max_age to more than 0 because that would break my site.
    – cherouvim
    Nov 13, 2019 at 12:30
  • Symfony should allow you to return any sensible cache control header. I understand that you don't want max_age >0, but you could set a s-maxage if you want the CDN to store the response.
    – 4uk4
    Nov 13, 2019 at 12:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.