Cache Configuration
An Armonic project uses several cache layers. Each layer has a different lifetime and must be configured for a specific purpose.
A practical setup separates:
- application and system caches managed by Symfony
- Doctrine metadata and query caches
- HTTP response storage and ESI processing
- CMS response caching and compiled content
Do not use a local cache for mutable data that must be immediately consistent across application instances.
Application And System Caches
Start with explicit adapters for cache.app and cache.system:
# config/packages/cache.yaml
framework:
cache:
prefix_seed: 'app_%env(APP_VERSION)%'
app: cache.adapter.filesystem
system: cache.adapter.apcu
This setup gives each cache a clear role:
cache.appstores application data on the local filesystemcache.systemstores framework and container-related data in local APCu memoryprefix_seedcreates stable namespaces and separates cache keys between application versions
APP_VERSION is a project environment variable. Set it to a value that changes with each deployment when cached data must not be reused by the new version.
Changing the prefix prevents the application from reading entries created by an older version. It does not necessarily delete those entries from the backend, so long-lived cache storage may still need pruning.
Local Cache Boundaries
Filesystem and APCu adapters are local to the application instance. They are a good fit for derived or disposable values that can be rebuilt.
Do not use them as the source of truth for:
- locks shared by several instances
- counters that must be globally accurate
- mutable state that must be visible immediately on every instance
- workflow or business data
Use the database or a shared cache backend for those cases.
Doctrine Caches
Doctrine metadata and parsed queries can reuse Symfony's system cache:
# config/packages/doctrine_cache.yaml
framework:
cache:
pools:
doctrine.system_cache_pool:
adapter: cache.system
doctrine:
orm:
query_cache_driver:
type: pool
pool: doctrine.system_cache_pool
metadata_cache_driver:
type: pool
pool: doctrine.system_cache_pool
This avoids creating a separate backend for data that is derived from code and mapping configuration.
The pool above stores query parsing and metadata information. It does not cache query results or Doctrine entities.
HTTP Cache And ESI
When a CDN or another reverse proxy is the shared HTTP cache, Symfony HttpCache can remain enabled only for ESI processing. In that deployment model, an in-memory store is enough:
# config/packages/http_cache.yaml
services:
http_cache.store.adapter:
parent: 'cache.adapter.array'
public: true
framework:
http_cache:
enabled: true
private_headers: ['Authorization']
trace_level: none
monolog:
channels: ['http_cache']
sfs_http_cache_store:
adapter: 'http_cache.store.adapter'
logger: 'monolog.logger.http_cache'
This configuration has deliberate limits:
cache.adapter.arrayis process-local and non-persistent- restarting the process removes its stored responses
- the upstream CDN or reverse proxy remains responsible for shared response caching
trace_level: noneavoids HttpCache trace information when it is not needed- the dedicated logger channel keeps cache activity identifiable in normal application logs
Use this model only when persistent HTTP response storage already exists outside the Symfony process.
Cookie And Authorization Safety
Setting private_headers to only Authorization means that a request containing cookies is not automatically treated as private by that rule.
Use this configuration only when cookie-bearing responses are safe to cache and the application sets Cache-Control, Vary, and private response rules correctly. Personalized responses must never enter a shared public cache.
When Symfony Is The Shared HTTP Cache
If Symfony HttpCache is responsible for storing shared responses, do not use cache.adapter.array. Configure a persistent pool that matches the deployment topology instead.
See HTTP cache store bundle for filesystem, Redis, Memcached, and dedicated pool options.
CMS Cache Strategy
The CMS can use TTL-based HTTP caching and versioned compiled content:
# config/packages/sfs_cms.yaml
sfs_cms:
cache:
type: 'ttl'
content:
save_compiled: true
recompile: false
prefix_compiled: '%env(ENVIRONMENT)%/%env(APP_VERSION)%/'
The options solve two different problems:
cache.type: ttlselects the CMS response cache strategysave_compiled: truestores compiled content for reuseprefix_compiledseparates compiled content by environment and application versionrecompile: falsedisables the manual content recompilation feature
ENVIRONMENT and APP_VERSION are project environment variables. A versioned prefix prevents a deployment from reusing compiled content that contains references generated by an older asset build.
CMS response caching and compiled content are not the same storage layer. Clearing Symfony cache does not remove compiled CMS data stored in the database. Changing prefix_compiled makes the CMS use a new compile key instead.
Recommended Baseline
For a container-based Armonic deployment:
- use filesystem cache for disposable application values
- use APCu for system and Doctrine metadata caches
- include the application version in cache namespaces
- use an in-memory HttpCache store only when a CDN or reverse proxy owns shared response caching
- use versioned CMS compile keys when deployments can change generated asset references
- keep shared mutable state in a shared backend or the database
Clearing The Right Cache
Clear Symfony application and system caches with the normal environment-aware command:
bin/console cache:clear --env=prod
Clear only the Doctrine system pool when that is the affected layer:
bin/console cache:pool:clear doctrine.system_cache_pool
An array-backed HttpCache store disappears with the process and does not need persistent cleanup. CMS compiled content requires its own lifecycle; use a new version prefix or the CMS recompilation flow rather than relying on cache:clear.
Common Mistakes
- treating local filesystem or APCu cache as shared application state
- using an array HttpCache adapter without an upstream shared cache
- changing
private_headerswithout reviewing personalized responses - assuming Doctrine's query cache contains query results
- expecting
cache:clearto remove compiled CMS content from the database - reusing one cache namespace across deployments with incompatible data or assets