bytes-commerce / module-cloudflare-cache
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
Requires
- php: >=8.1 <9
- ext-json: *
- magento/framework: >=103.0 <105
- magento/module-cache-invalidate: >=100.4 <101
- magento/module-config: >=101.2 <102
- magento/module-page-cache: >=100.4 <101
- magento/module-store: >=100.0 <102
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
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:
-
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 tono-storeright 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 aspublic, max-age=0, s-maxage=<edge ttl>: the browser refetches the page, Cloudflare may keep it. -
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_42for a product,cat_c_7for a category,cms_p_3for a CMS page). Those tags are mirrored into Cloudflare'sCache-Tagresponse header while the page is stored, so every later cache hit replays them. Whenever Magento raisesclean_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/framework103 or 104) - PHP 8.1 and later
- A Cloudflare zone that proxies the storefront
- A Cloudflare API token with the permissions
Zone:ReadandZone: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.