I have a Controller using cache tags. I have just been asked a change that requires a Max-age also (show next event starting from current time); I explained that the only way to have this is with some delay, and we agreed for a max-age of 300.

To test the modification on my development machine, I set a shorter max-age of 60,

        return [
            '#theme' => 'mytheme',
            '#my_param' => $value,
            '#cache' => [ 
                'tags' => $cache_tags,
                'max-age' => 60,

I loaded the page just after a drush cr, and in the header I got a clear X-Drupal-Cache: MISS. I loaded it again, and I got a HIT. Then I waited for a minute... and I got a HIT again.

Should I be looking for something else? I noticed a X-Drupal-Dynamic-Cache header also, but it is always set to MISS.

EDIT: From the comments I understood that I cannot set a max-age on a page with anonymous access, so the question changes: is there any other workaround, apart from disabling cache on this page, that would have a big impact on performance?

  • 2
    X-Drupal-Cache is for the anonymous user caching of the whole page. It's well documented that setting a max-age has no effect on this caching unfortunately. So max-age will only affect X-Drupal-Dynamic-Cache. This only becomes active if you are logged in (or you disable the anonymous caching). Also if you are logged in with an admin account things like the admin toolbar will always cause a MISS on X-Drupal-Dynamic-Cache. So best to try with normal user logged in account Feb 14, 2023 at 16:34
  • 3
    Usually it's better to invalidate a cache after a change has been made, rather than setting a max age, as max-age adds to performance hits. That's not an absolute rule, but you didn't tell us your use case. Is there a specific reason to use max-age rather than invalidating a cache tag?
    – Jaypan
    Feb 14, 2023 at 16:38
  • 2
    max-age does not bubble drupal.org/project/drupal/issues/2352009
    – cilefen
    Feb 14, 2023 at 17:15
  • @unusedspoon, the page in question is a public page, so yes, it was accessed by the the anonymous user. Now that you mention it, I remember reading that max-age has no effect on this caching; I didn't search the documentation because, well, I often find it difficult to look things up in Drupal documentation, especially when I don't know exactly what I'm looking for... Feb 15, 2023 at 8:19
  • @Jaypan, I described it quickly between parentheses: I have to show the next event starting from current time, so it changes even if no content is changed. Suppose for example that there is an event starting at 11:00 and one at 14:30: at 10:59 I have to show the first, at 11:01 I should show the second. As I said, I negotiated a delay of five minutes, so the worst case is that the page is updated with a five minutes delay, i.e., the page would show the event at 11:00 until 11:05, and then the one at 14:30 would appear. Feb 15, 2023 at 8:22

1 Answer 1


To extend on the comments. At this moment the only caching method implemented for anonymous traffic is cache tags. Context or max-age don't work. Cache tags are great for database content, this is the use case of Drupal out-of-the-box. But you can use cache tags for a time-based invalidation as well. In a cron job:


use Drupal\Core\Cache\Cache;

 * Implements hook_cron().
function mymodule_cron() {
  $cache_tags = ['foo'];
  if (date('H') == 12 ) {

This invalidates the controller output every 24h at noon. Make sure to trigger cron at least every hour.

To achieve the max-age of 300, trigger cron every 5 min, or when events usually start in your schedule. Go to /admin/config/system/cron, get the link with the long hash code, and wget it in the cron table of your web host.

Then run the cron hook without condition:

function mymodule_cron() {
  $cache_tags = ['foo'];

Don't forget to configure "Browser and proxy cache maximum age" in the Performance configuration page accordingly.

  • Thank you @4uk4, I guess this is my only possibility. I already have a couple of routes configured with _access_system_cron and invoked from the host cron, so I will implement this solution. Feb 15, 2023 at 8: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.