CWA 2.0 is in alpha: try it, build with it, give feedback. APIs can still change between releases; see Releases.
Overview

Caching

Every cache between a visitor and the API in a CWA site, from the service worker to Cloudflare, Souin and the API's cache tags. What each one stores, how long, and what clears it.

A CWA page can be served from several caches before it reaches the API. Each one has its own page in these docs. This page shows how they fit together, so you can follow one request through all of them.

The key idea: the API decides what may be cached, and the API purges it. Every cacheable response is tagged with the IRIs of the resources in it. When an editor saves a resource, the API sends that IRI as a purge, and every cached response that used the resource is dropped. So caches can keep responses for a long time and still never show stale content.

The layers

A visitor's request passes through these layers, outermost first. Only a miss goes on to the next one.

Browser ── service worker (cwa-api cache, read only when offline)
   │
   ▼
Cloudflare (optional) ── edge cache, only with Option B
   │
   ▼
Caddy in the php container ── Souin: page HTML and /_api responses
   │                 │
   │ page miss       │ /_api miss
   ▼                 ▼
Nuxt (SSR)  ───────▶ API (Symfony) ── sets Cache-Control and the cache tags
   │                          │
   └── tags the page          └── purges tags when a resource is written
       with every IRI it used
Diagram placeholder: a layer diagram in the style of DiagramCiPipeline. Left to right: browser and service worker, Cloudflare (dashed, optional), Caddy with Souin, then Nuxt SSR and the API side by side. Arrows for a request going in and a miss going on. A second colour for purges: the API sending tags to Souin, and Souin forwarding them to Cloudflare.

What each layer does

LayerWhat it cachesHow longWhat clears itDetails
Browser HTTP cacheNothing from CWA except built files. Pages and API responses send max-age=0Built /_nuxt files are immutableA new build gives the files new namesPage Caching
Service workerThe app shell, and public API responses in a cwa-api cache, which is only read while offlineUp to 4 hours in the templateA response marked private or no-store is never stored. The module deletes cwa-api when a session endsPWA & Offline
Cloudflare (optional)Nothing with Option A, the recommended default. Page HTML with Option BThe origin's s-maxageSouin forwards each tag purge to Cloudflare. A full flush sends Purge EverythingCloudflare
Souin in CaddyPage HTML that Nuxt rendered, and /_api responsesThe response's s-maxage: one year in the template's production API, 60 seconds in developmentA tag purge from the API, a full flush, or a php restart, because the template's store is in memoryThe HTTP cache in Caddy
Nuxt page taggingNothing itself. It sets the headers that let Souin store a pageThe lowest s-maxage of the API responses the page used, capped by pageCache.sharedMaxAgePurged with the resources it used. Every page carries the cwa-html tag tooPage Caching
API cache tagsNothing itself. It marks each response and sends purgesShortened ahead of a scheduled publish or route go-liveWriting a resource purges its IRI. Saving site config purges cwa-htmlHTTP Caching

Signed-in editors never get a cached page

Draft and published content share the same URLs. The API tells them apart by the auth cookie, not the URL. So the API marks an editor's responses for routes, manifests, positions and publishable components private, no-store, and the module marks an editor's pages the same way. A cache only ever holds what an anonymous visitor sees. See HTTP Cache Safety.

Only CWA data is tagged. Anything else a page renders on the server, such as a third-party fetch or the current date, is never purged. Set pageCache.sharedMaxAge to cap how long such pages are kept. See How Long a Page Is Kept.

Purges

What happensWhat is purged
An editor saves a resourceThat resource's IRI, so every response and page that used it
An editor saves site configcwa-html, so every rendered page
A scheduled publish or route go-live arrivesNothing: the API shortened the lifetimes in advance, so those responses have already expired
A deployEvery rendered page (cwa-html), or the whole cache when Cloudflare edge caching is set up. The pipeline then warms the cache
Purge all cached data in site settings, purge-http-cache, or a fixture loadThe whole HTTP cache
purge-http-cache --path or --tagOne page, or any tag

See Purging All Cached Data, Purging One Page and CI/CD → Why every deploy clears the page cache.

Protecting the origin

A cache only helps if made-up URLs can't get past it. The template's Caddyfile drops query parameters that pages don't read, strips tracking parameters, and rate-limits requests that miss the cache. On Kubernetes, ingress-nginx can add an outer rate limit, and php sheds load when every worker is busy. See Origin Protection.

Next: Glossary

The Glossary defines every CWA term used in these docs, including the caching ones.