Search by

bytes-commerce / module-cloudflare-cache

bytes-commerce

Cloudflare edge caching for Magento 2: makes cacheable storefront pages eligible for the Cloudflare edge and invalidates them by cache tag when Magento cleans its own cache.

Package info

github.com/bytes-commerce/module-cloudflare-cache

Type:magento2-module

pkg:composer/bytes-commerce/module-cloudflare-cache

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0 2026-11-13 23:05 UTC

This package is auto-updated.

Last update: 2026-11-13 23:25:29 UTC


README

Cloudflare edge caching for Magento 2, built on the cache tags Magento already maintains.

The module does two things:

  1. It makes cacheable storefront pages eligible for the Cloudflare edge. Magento renders a cacheable page with Cache-Control: public, max-age=<ttl>, s-maxage=<ttl> and then rewrites that header to no-store right before the page is written to the full page cache. That default keeps every intermediary, including Cloudflare, from caching the page. The module keeps the public header but removes the browser lifetime, so the response leaves Magento as public, max-age=0, s-maxage=<edge ttl>: the browser refetches the page, Cloudflare may keep it.

  2. It invalidates the edge cache when Magento invalidates its own cache. Magento collects the identities of the blocks a page is built from (cat_p_42 for a product, cat_c_7 for a category, cms_p_3 for a CMS page). Those tags are mirrored into Cloudflare's Cache-Tag response header while the page is stored, so every later cache hit replays them. Whenever Magento raises clean_cache_by_tags, the same tags are purged at the edge.

Requirements

  • Magento Open Source or Adobe Commerce 2.4.7 or 2.4.8 (magento/framework 103 or 104)
  • PHP 8.1 and later
  • A Cloudflare zone that proxies the storefront
  • A Cloudflare API token with the permissions Zone:Read and Zone:Cache Purge

Installation

composer require bytes-commerce/module-cloudflare-cache:@dev && bin/magento module:enable BytesCommerce_CloudflareCache && bin/magento setup:upgrade && bin/magento setup:di:compile && bin/magento cache:clean

In production mode also run bin/magento setup:static-content:deploy.

The package is published on Packagist. Only the dev-master branch is published so far, which is why the requirement carries the :@dev constraint. Once a release is tagged, the constraint is no longer needed and the install reduces to:

composer require bytes-commerce/module-cloudflare-cache

Configuration

Stores > Configuration > BytesCommerce > Cloudflare Cache

Field Meaning
Enable Cloudflare cache Master switch. When off, no response header is changed and nothing is purged.
API token Cloudflare API token, encrypted at rest.
Zone ID The zone that serves the storefront.
Make cacheable pages edge cacheable Rewrites the cache-control header as described above.
Edge TTL How long Cloudflare may keep a cached page. Also becomes the lifetime of the matching full page cache entry.
Send Cache-Tag header Mirrors X-Magento-Tags into Cache-Tag.
Purge mode Purge by cache tag, by URL, or everything.
Queue purges Collect purges in a queue and send them in batches.
Tags per purge request Maximum number of tags per request, Cloudflare accepts up to 100.
Excluded tag patterns Comma separated patterns of tags that are never purged, for example gql_*.

Working on the module in a store

The module is consumed as a Composer path repository. Changes in the module directory are not picked up automatically, because Composer copies the package into vendor/ instead of linking it: the static content deployer resolves the real path of every module and refuses paths that lie outside the Magento root, which a symlink into vendor/ would produce.

After changing the module, run:

composer install                                    # copies the module from bc/ into vendor/
bin/magento setup:di:compile                        # only when the dependency injection changed
bin/magento setup:static-content:deploy -f

composer install is enough and is the safer choice: it takes the package from the lock file, so the copy in vendor/ is always taken from the module directory. composer update bytes-commerce/module-cloudflare-cache caches the package metadata and can leave a stale copy behind - if that happens, remove vendor/bytes-commerce/module-cloudflare-cache, run composer clear-cache and composer install again.

The Cloudflare side

The module expects a cache rule that honours the origin's cache headers, which is the default behaviour of Cloudflare. No rule has to be created for the module to work, but the zone needs the paths that carry session, customer, checkout or third party callback context excluded. The module never marks such a response as cacheable, so a plain cache rule is enough.

To see whether a page is edge cacheable, compare the response headers of the first and the second request for the same URL. The second request is answered from the full page cache and carries Cache-Control: public, max-age=0, s-maxage=<edge ttl> and a Cache-Tag header.

Command line

# check the connection and the state of the queue
bin/magento bc:cloudflare:health

# purge by cache tag
bin/magento bc:cloudflare:purge --tag=cat_p_42 --tag=cat_c_7

# purge everything
bin/magento bc:cloudflare:purge --all

# send the queued purges
bin/magento bc:cloudflare:purge --drain

How it works

Component Purpose
Plugin/Framework/App/Response/HttpPlugin Rewrites the cache-control header and keeps the page cache kernel from turning it back into no-store.
Plugin/Framework/App/PageCache/KernelPlugin Mirrors X-Magento-Tags into Cache-Tag while the page is stored.
Observer/PurgeByTagsObserver Purges the tags of the entity Magento invalidated.
Observer/FlushAllObserver Purges everything when Magento flushes its caches.
Model/PurgeQueue Collects purges and sends them in batches of at most 100 tags.
Cron/DrainPurgeQueue Sends the queued purges on Magento's default cron schedule.

The session cookie

Magento starts a PHP session for every storefront request and PHP sends a PHPSESSID with it. Cloudflare never caches a response that carries a Set-Cookie header. Magento removes that header itself as soon as a page is written to the full page cache, so a cacheable page leaves the shop without a cookie and can be cached at the edge.

The consequence is that a visitor who is served from the edge has no session until a request that is not cached runs. The mini cart is loaded over customer/section/load, which is never cached, so the cart keeps working. A visitor that already carries a session cookie is never served from the edge.

License

OSL-3.0. See LICENSE.