Skip to header Skip to main navigation Skip to main content Skip to footer
Cookies UI
Alaa Haddad Offers Exceptional Drupal Custom Theming and Modules in Austin TX Alaa Haddad - Drupal Expert
Main navigation
  • Professional Profile
  • Drupal Services
    • Drupal Development
    • Drupal Developer
    • Drupal Themer
    • Drupal Architect
    • Drupal Consultant
  • My Drupal Modules & Themes
      • Cloudflare Purge
      • Solo Copy Blocks
      • W3CSS Paragraphs
      • Paragraphs Bundles
      • Acquia Purge Varnish
      • Reference Blocked Users
      • Module Matrix
      • Paragraphs Bundles Import
      • Selectify
      • Solo Utilities
      • Utilikit
      • Solo
      • Amun
      • Anhur
      • Amunet
      • W3CSS Theme
      • 3D Carousel
      • 3D FlipBox
      • Accordion
      • Carousel
      • Hero
      • Lightbox
      • Parallax
      • Reveal
      • Slideshow
      • Tabs
  • Blog
  • Videos
  • Contact
  • Hire Me (opens in new tab)
Search form
User login
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
  • Reset your password
User account menu
  • Hire Me (opens in new tab)
  • Drupal Services
  • Blog
Site branding
Alaa Haddad - Drupal Expert
Consultant • Architect • Developer • Themer - Expert Drupal Solutions
Article Title Image - Block 1

Drupal and Cloudflare Caching: Long Edge TTLs, Safe Purging

Content Info - Article Info
 
  10:55 PM CDT, Sun September 13, 2026
Share

Breadcrumbs

Breadcrumb

  • Home
  • Cloudflare Purge
  • Drupal and Cloudflare Caching: Long Edge TTLs, Safe Purging

Main page content

Cache max-age and cache purging are two different instructions, and a fast, accurate Drupal site needs both: long lifetimes at the Cloudflare edge for speed, and a reliable purge on content change so nobody sees a stale page.

Almost every "why is my Drupal site still showing the old text?" question comes from treating those two things as one setting. They are not. Max-age answers how long may this response stay fresh. A purge answers delete this copy now, because it changed. Get the split right and you can cache anonymous pages at the edge for a month without ever serving stale content.

The three cache layers in a Drupal + Cloudflare stack

For an anonymous visitor, a request can be answered at any of three points before Drupal is asked to build anything:

Visitor browser
  |
Cloudflare edge cache
  |
Drupal origin (internal page cache / dynamic page cache / render cache)
  • Browser cache — private to one visitor. You cannot purge it. Whatever Cache-Control: max-age you sent is what that browser will honour.
  • Cloudflare edge cache — shared, and you can purge it via the API.
  • Drupal's own caches — page cache for anonymous users, dynamic page cache for authenticated, plus the render cache, all keyed by cache tags and contexts.

The one that catches people out is the first. A Cloudflare purge does nothing to a page already sitting in a visitor's browser. That single fact drives the whole configuration below.

What max-age actually sets

In Drupal, the browser and proxy cache maximum age is a real config key with an integer value. Core ships it at 0 — verified in core/modules/system/config/install/system.performance.yml on Drupal 11.4.6. The Performance UI exposes a fixed list of values; anything else you set in settings.php:

$config['system.performance']['cache']['page']['max_age'] = 3600;

That header goes to both browsers and shared caches. Which is exactly why a one-year value there is a trap for HTML. Long browser caching is right for versioned CSS, JavaScript, fonts and images. It is wrong for a page an editor will change on Tuesday.

The pattern that works: short at the browser, long at the edge

Split the two audiences. Send a modest max-age from the origin, then let a Cloudflare Cache Rule hold the response at the edge for far longer, and purge the edge when Drupal says the content changed.

Recommended starting configuration for an anonymous-heavy Drupal content site
LayerSettingWhy
Drupal max_age3600 (1 hour) or 86400 (1 day)Safe if a purge ever fails; short enough that a browser self-corrects.
Cloudflare Edge Cache TTL1 month to 1 yearPurgeable, so a long value costs nothing.
Cloudflare Browser Cache TTLRespect originDo not let the CDN extend HTML caching in browsers behind your back.
Purge triggerDrupal cache-tag invalidationFires exactly when a node, block or menu changes.

The shorthand is cache long, purge on change. The long TTL buys the performance; the purge buys the accuracy. Neither works well alone.

Using s-maxage to say it in one header

If you would rather express the split at the origin than in a Cloudflare rule, s-maxage applies only to shared caches:

Cache-Control: public, max-age=300, s-maxage=31536000

Browsers treat it as fresh for five minutes; Cloudflare treats it as fresh for a year. Apply it narrowly — to known-public anonymous routes — never globally.

If your site is slow for reasons that have nothing to do with the CDN, the groundwork is elsewhere: see the five changes that make any site faster before you tune TTLs. And if you would rather someone else owned the whole caching layer, that is exactly what Drupal services covers.

Per-route control from Drupal

When only some routes should get the aggressive header, do it in a response event subscriber, not in hook_page_attachments_alter() — that hook is for attachments, not HTTP headers.

<?php

declare(strict_types=1);

namespace Drupal\my_module\EventSubscriber;

use Drupal\Core\Session\AccountProxyInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

final class ResponseCacheControlSubscriber implements EventSubscriberInterface {

  public function __construct(
    private readonly AccountProxyInterface $currentUser,
  ) {}

  public static function getSubscribedEvents(): array {
    return [KernelEvents::RESPONSE => ['onResponse', -10]];
  }

  public function onResponse(ResponseEvent $event): void {
    if (!$event->isMainRequest() || $this->currentUser->isAuthenticated()) {
      return;
    }
    $request = $event->getRequest();
    if ($request->getMethod() !== 'GET') {
      return;
    }
    if (!in_array((string) $request->attributes->get('_route'), ['<front>', 'entity.node.canonical'], TRUE)) {
      return;
    }
    $response = $event->getResponse();
    if (!$response->isSuccessful() || $response->headers->has('Set-Cookie')) {
      return;
    }
    $response->headers->set('Cache-Control', 'public, max-age=300, s-maxage=31536000');
  }

}

Note the guard clauses. Anonymous only, GET only, named routes only, successful responses only, and never when a Set-Cookie header is present. Every one of those exists to stop a personalised response reaching a shared cache. On a Drupal 12 target, remember getSubscribedEvents() must declare its : array return type or Symfony 7 fatals at container build.

What must never be cached at the edge

A Cloudflare Cache Rule that ignores origin headers too broadly will happily cache something Drupal marked private. Exclude, at minimum:

  • /admin/* and /user/*, including /user/login and /user/logout
  • Cart and checkout routes on Commerce sites
  • Webform confirmation pages that echo submitted values
  • Anything rendered per-user, per-role or per-session

Scope the rule to the paths you know are public rather than caching everything and carving out exceptions. Fail closed on data access — the cost of a wrong guess here is one visitor seeing another's page.

Choosing the purge integration

I maintain the Cloudflare Purge module, so I will be plain about where it fits. Read from its cloudflare_purge.info.yml: core_version_requirement: ^10 || ^11 || ^12, php: ^8.1, and its only dependency is drupal:system.

That single line is the whole design decision. It does not require the purge module stack, and it uses the Guzzle client already in core rather than raw cURL. It handles purge-everything, purge by URL (Cloudflare caps a request at 100 URLs), by cache tag, by prefix and by hostname; it can purge automatically when Drupal invalidates a cache tag; it queues requests for cron-time batching; and it ships Drush 13 commands. Credentials can live in the Key module or be overridden from settings.php so they never enter config or git.

It is the right choice when you are on a Cloudflare-partner host without dashboard access, or when you want the invalidation without adopting the full purge ecosystem. If you already run purge with several queue backends, stay there.

How to verify it, not assume it

curl -sI https://example.com/about-us | grep -iE 'cache-control|cf-cache-status|age|set-cookie'
curl -sI https://example.com/user/login | grep -i cf-cache-status

CF-Cache-Status: HIT means Cloudflare served it; MISS means it went to origin. Immediately after a purge, a MISS is correct and expected. The second command is the one people skip: confirm your sensitive routes are not being cached before you widen the rule.

Common questions

Does purging Cloudflare change my max-age?

No. Purge deletes copies that already exist. Max-age governs how long the next copy is allowed to stay fresh. Changing one never changes the other.

Why do I still see the old page after a successful purge?

Almost always your own browser cache. Purge cleared the edge; your browser is still honouring the max-age it was given earlier. Test in a private window or with curl, which has no cache.

Can I set a one-year max-age in Drupal and be done?

For static assets, yes. For HTML, no — you would be handing every visitor a copy you have no way to recall. Keep HTML short at the browser and long at the edge.

Do I need cache tags configured for this to work?

Drupal emits cache tags automatically for nodes, blocks, menus, views and config. The purge integration listens for those invalidations. You only need custom tags when you render something Drupal cannot see is dependent on it.

What if the purge API call fails?

This is why the origin max-age stays modest. A failed purge with a one-hour max-age means an hour of staleness at worst. A failed purge with a one-year max-age means a year. Design the failure path first.

Where to go next

Caching sits on top of everything else, so it is worth getting the layer underneath right too — how Drupal renders blocks and why they duplicate is a common source of pages that cache badly because they render twice.

If you want this configured and proven on your site rather than described, two routes: Drupal development services covers the module and event-subscriber work, and get in touch if you would rather start with a look at what your headers are doing today.

Cloudflare Purge
Drupal Caching
cache invalidation
Edge Cache TTL
Slide 1 of 27
Acquia Purge Varnish - API V2 (Drupal Module)
Slide 2 of 27
Amun - W3CSS Sub-Theme (Drupal Theme)
Slide 3 of 27
Amunet - W3CSS Sub-Theme (Drupal Theme)
Slide 4 of 27
Anhur - W3CSS Sub-Theme (Drupal Theme)
Slide 5 of 27
Cloudflare Purge (Drupal Module)
Slide 6 of 27
Module Matrix (Drupal Module)
Slide 7 of 27
Paragraphs Bundles (Drupal Module)
Slide 8 of 27
Paragraphs Bundles Import (Drupal Module)
Slide 9 of 27
Reference Blocked Users (Drupal Module)
Slide 10 of 27
Selectify (Drupal Module)
Slide 11 of 27
Solo (Drupal Theme)
Slide 12 of 27
Solo Copy Blocks (Drupal Module)
Slide 13 of 27
Solo Utilities (Drupal Module)
Slide 14 of 27
Utilikit (Drupal Module)
Slide 15 of 27
Views 3D Carousel (Drupal Module)
Slide 16 of 27
Views 3D FlipBox (Drupal Module)
Slide 17 of 27
Views Accordion (Drupal Module)
Slide 18 of 27
Views Carousel (Drupal Module)
Slide 19 of 27
Views Hero (Drupal Module)
Slide 20 of 27
Views Lightbox (Drupal Module)
Slide 21 of 27
Views Parallax (Drupal Module)
Slide 22 of 27
Views Reveal (Drupal Module)
Slide 23 of 27
Views Slideshow (Drupal Module)
Slide 24 of 27
Views Tabs (Drupal Module)
Slide 25 of 27
VVJ Core (Drupal Module)
Slide 26 of 27
W3CSS Paragraphs (Drupal Module)
Slide 27 of 27
W3CSS Theme (Drupal Theme)
1 of 27

Our mission is to make Drupal more accessible and user-friendly, empowering businesses of all sizes, especially small enterprises with powerful tools that streamline content customization and enhance digital experiences.

Need help with your Drupal project? Hire Me through Flash Web Center, LLC.

Search

The Drupal 11 Module and Theme Stack, With Versions Checked

ARIA Live Regions in Drupal 11: What Core Does, What You Add

Drupal Architect: The Decisions Expensive to Reverse

Drupal Services: Development, Theming, Upgrades | Austin TX

Paragraphs Bundles

Drupal Module - Paragraphs Bundles

Drupal Theme - Solo

Drupal Theme - Solo

Drupal Work List - Drupal Work

Reference Blocked Users (Drupal Module)

Solo Utilities (Drupal Module)

Views Hero (Drupal Module)

Solo (Drupal Theme)

Paragraphs Bundles Import (Drupal Module)

Drupal Theme - W3CSS Theme

Drupal Theme - W3CSS Theme

Drupal Module - W3CSS Paragraphs

Drupal Module - W3CSS Paragraphs

Inspiration

Inspiration is the fuel that powers our creative engine, often coming from our surroundings, experiences, or the works of others. It's that magical moment when something clicks inside your brain, and you suddenly see a path forward that you hadn't noticed before. Inspiration can strike at any time, providing the motivation and energy needed to explore new possibilities and bring your ideas to life.

Unique Ideas

Unique Ideas

Unique ideas are the seeds of innovation, representing original thoughts or concepts that stand out from the usual. They're the sparks that ignite the process of creating something new and different, often leading to unexpected and groundbreaking solutions or products. Whether in art, science, business, or technology, unique ideas challenge the status quo and pave the way for progress.

Brainstorming

Brainstorming

Brainstorming is a creative group activity designed to generate a large number of ideas or solutions to a problem. It's a free-flowing and open-ended discussion where every suggestion is welcomed and considered, no matter how outlandish it may seem. Brainstorming encourages thinking outside the box, fostering an environment where creativity and collaboration lead to innovative solutions.

Planning

Planning

Planning is the blueprint for turning your ideas into reality. It involves setting goals, outlining steps, and organizing resources in a way that makes achieving your objectives possible. Good planning considers potential challenges and opportunities, making it easier to navigate the journey from concept to completion. It's about preparing the groundwork so that your projects can grow and flourish.

Drupal Developer

A Drupal Developer stands as the technical powerhouse behind dynamic websites, wielding expertise in PHP, custom module development, and Drupal's sophisticated API ecosystem. This role transforms business requirements into functional, secure, and scalable web solutions that power everything from small business sites to enterprise platforms serving millions of users. A Drupal Developer's expertise spans the entire development lifecycle—from architecting custom modules and integrating third-party services to optimizing performance and ensuring security compliance. Discover the complete guide to Drupal Developer skills, career paths, and hiring strategies.

Drupal Themer

A Drupal Themer serves as the artistic craftsperson who transforms wireframes and design mockups into pixel-perfect, accessible, and responsive user experiences using Twig templates, CSS, and JavaScript. This specialized role bridges the gap between design vision and technical implementation, ensuring every website not only looks exceptional but performs flawlessly across all devices and meets WCAG accessibility standards. A Drupal Themer's work encompasses the entire front-end ecosystem—from creating custom theme architectures and optimizing Core Web Vitals to implementing complex responsive designs and ensuring seamless integration with Drupal's rendering system. Explore the comprehensive guide to Drupal Themer expertise, theming best practices, and career advancement.

Drupal Architect

A Drupal Architect emerges as the strategic visionary of web construction, armed with encyclopedic knowledge of enterprise architecture patterns, infrastructure design, and Drupal's extensive technological ecosystem. This senior role operates at the highest technical level, making critical decisions that determine whether complex implementations scale successfully or collapse under real-world demands. A Drupal Architect's responsibilities begin long before development starts—during strategic planning phases where the foundation for secure, performant, and maintainable systems is established through careful evaluation of technology stacks, integration strategies, and scalability requirements. Learn about Drupal Architect skills, enterprise architecture strategies, and career progression to principal roles.

Footer menu

  • Contact
  • Professional Resume
  • Resume Summary
  • Technical Skills
  • Privacy Policy
  • Terms & Conditions
  • Search
  • Login
  • Sitemap

Copyright © 2026 Flash Web Center, LLC - All rights reserved

Developed & Designed by Alaa Haddad