Caching layers for engineers
This page is for engineers who reason about performance and correctness together. Exponential has many caches; most performance work is choosing which to switch on, and most "stale page" bugs are one of them answering when it should not. The operator's view of the same layers is Caching layers, and the administration page is described in Caches.
Contents
- The layers in order
- What each layer is keyed on
- Shared or per node
- Correctness risks
- Choosing what to switch on
The layers in order
From the visitor down to the database:
| # | Layer | Ships | Serves | Source |
|---|---|---|---|---|
| 1 | Browser cache of static files | Velocity: StaticMaxAge one year | everyone | HTTP caching |
| 2 | Browser cache of pages | off ([HTTPHeaderSettings]) | anonymous visitors, when switched on | HTTP caching |
| 3 | CDN or caching proxy | not part of Exponential | as configured | Exponential sends no purges |
| 4 | Velocity response cache | on under Velocity (velocity.ini [CacheSettings] Enabled=enabled) | anonymous visitors | Velocity response cache |
| 5 | Role-aware HTTP cache | off (httpcache.ini) | anonymous and signed-in, per permission context | HTTP cache |
| 6 | Static cache | off | anonymous visitors, as files | Static cache defaults |
| 7 | Content view cache | on ([ContentSettings] ViewCaching=enabled) | every visitor | Caches |
| 8 | Template block cache | on ([TemplateSettings] TemplateCache=enabled) | every visitor | The template engine and the design chain |
| 9 | Compiled templates, INI and override caches | on | every request | Caches |
| 10 | Redis or Valkey for views, blocks, INI | only with sevenx_valkey_cache | every request | sevenx_valkey_cache |
| 11 | SQL query cache | off (querycache.ini Mode=off) | every request it can answer | The SQL query cache |
| 12 | OPcache, APCu | per PHP process | every request | your PHP configuration |
The Velocity response cache exists only under the qbix engine: FrankenPHP has none yet, and PHP-FPM behind Apache
or nginx has none of its own (Application servers).
What each layer is keyed on
| Layer | Key (in short) | Invalidated by |
|---|---|---|
| Velocity response cache | the request of an anonymous visitor; lifetime [CacheSettings] DefaultTtl (30 seconds shipped) unless the page's Cache-Control says otherwise | lifetime, ./console exp:velocity cache clear --apply |
| Role-aware HTTP cache | the content view and the permission context (anonymous, a shared role context, or private) | content change purges (ContentChangePurges=all by default), --clear-id=exphttpcache |
| Content view cache | the node, the view and its parameters, and the user's access context | eZContentCacheManager on publish, --clear-tag=content |
| Template block cache | the keys written in {cache-block}, and its expiry | expiry, --clear-id=template-block |
| INI cache | the files of the cascade for a siteaccess (and environment) | --clear-tag=ini |
| SQL query cache | the SELECT statement | a write to one of the tables it read |
Shared or per node
The caches in var/ are files written through the cluster file handler, so the same code can share them on clustered
storage. Velocity's response cache and the in-memory state of its workers are per server process; OPcache and APCu are
per PHP process. With several web nodes, decide for each layer whether it is shared, purged on every node, or allowed
to expire (Scaling and clustering).
Correctness risks
- Clearing before reloading. A page rendered by the old code between a cache clear and the reload of PHP-FPM or Velocity is cached again; clear page caches last (Deploying a change).
- Writes from outside. A restore or a SQL client write bypasses the SQL query cache's invalidation; clear it afterwards.
- Cache blocks without the right keys. A
{cache-block}that does not key on what changes the output serves one user's or one page's fragment to another. - Velocity keeps settings in memory. After an INI change, clearing the INI cache is not enough under Velocity; restart it.
- Static cache. With it on, every publish regenerated every affected page over HTTP inside the editor's request; the project ships it off and recommends leaving it off.
Choosing what to switch on
- Keep the shipped defaults: view cache, template blocks, compiled templates, INI cache.
- For anonymous traffic, under Velocity, the response cache gives the largest gain per change.
- For signed-in traffic, the role-aware HTTP cache keeps whole views per permission context.
- For pages that cannot be stored whole (the administration, private contexts, scripts), the SQL query cache.
- For several web nodes, consider Redis or Valkey for views, blocks and INI.
Measure each step (Performance measurement and benchmarks).
Related pages
- Cache invalidation and clearing
- Caching in applications
- The response cache, and getting out of the network's way
- Free documentation: this page is free to copy, translate and improve under the GNU FDL 1.3.
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.