How to speed up Drupal with the right caches: OPcache, APCu, and a shared backend (Redis or Memcached)
If your Drupal site feels slow, caching is usually the fix. Not a single fix, though. Different layers solve different problems. That is why OPcache, APCu, and a shared backend such as Redis or Memcached often show up together. Each one speeds up a specific part of the stack. Use them well and Drupal becomes snappy. Use them poorly and it still drags.
Warning: pick one shared backend for Drupal cache bins. Use Redis or Memcached, not both for the same bins.
At a glance: must do vs advanced
- Must do: Enable OPcache in PHP. Turn on APCu for local caches. Choose one shared backend for bins on multi server setups.
- Advanced: Map specific bins, tune Redis client timeouts, adjust Memcached item size, compress large Redis values, size pools based on real usage.
Quick decision guide
Setup | Must do | Shared backend | Best for | Notes |
---|---|---|---|---|
Single server | OPcache + APCu | Optional | Small sites on one node | DB cache may be fine. Add Redis or Memcached if traffic grows. |
Multiple servers | OPcache + APCu | Redis or Memcached | Load-balanced clusters | Use one shared backend for render, dynamic page cache, page, default, data. |
High variability content | OPcache | Redis | Complex tagging and invalidation | Structures and persistence options help. |
Lean and simple | OPcache | Memcached | Pure caching with minimal overhead | Very fast, ephemeral by design. |
What each cache does
- OPcache: Speeds up PHP itself by caching compiled scripts.
- APCu: Local, per server key value cache for tiny lookups.
- Redis: Shared in memory data store for caches, queues, locks, sessions.
- Memcached: Shared in memory key value cache, very simple and fast.
How these fit into Drupal
- OPcache: Enable at the PHP layer. Not a Drupal module.
- APCu: Serve local caches and bootstrap data.
- Redis or Memcached: Map render, dynamic page cache, page, default, data to the shared backend. Also support sessions, locks, and queues.
Related: State cache (Drupal 10.3+, on by default in Drupal 11). See the separate post for details: Speed up the Drupal backend with $settings['state_cache']
.
Pro Tip: On multi-server setups, keep bootstrap in APCu for ultra low latency, and move the rest to the shared backend.
settings.php quick recipes
Paste, then adapt.
Redis
Drupal integration
$settings['container_yamls'][] = 'modules/contrib/redis/redis.services.yml';
$settings['redis.connection']['interface'] = 'PhpRedis';
$settings['redis.connection']['host'] = '127.0.0.1';
$settings['redis.connection']['port'] = 6379;
$settings['cache']['default'] = 'cache.backend.redis';
$settings['cache']['bins']['render'] = 'cache.backend.redis';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.redis';
$settings['cache']['bins']['page'] = 'cache.backend.redis';
Performance tuning
// Optional compression
$settings['redis_compress_length'] = 100;
$settings['redis_compress_level'] = 1;
// Client timeouts (PhpRedis)
$settings['redis.connection']['timeout'] = 1.0;
$settings['redis.connection']['read_timeout'] = 1.0;
$settings['redis.connection']['retry_interval'] = 100;
$settings['redis.connection']['persistent'] = TRUE;
- container_yamls: Registers Redis services.
- interface: Chooses client. PhpRedis is native extension.
- host/port: Specifies connection target. Prefer Unix socket on same host.
- cache.default: Sets default backend for unmapped bins.
- bins: Maps specific bins to Redis.
- compress_length/level: Compresses large values to save memory.
- timeouts/persistent: Sets connect/read timeouts and reuses connections.
Memcached
Drupal integration
$settings['container_yamls'][] = 'modules/contrib/memcache/memcache.services.yml';
$settings['memcache']['servers']['127.0.0.1:11211'] = 'default';
$settings['memcache']['bins']['render'] = 'default';
$settings['memcache']['bins']['dynamic_page_cache'] = 'default';
$settings['memcache']['bins']['page'] = 'default';
$settings['cache']['default'] = 'cache.backend.memcache';
- container_yamls: Registers Memcache services.
- servers: Defines server list and pool name.
- bins: Maps bins to a pool.
- cache.default: Sets default backend for unmapped bins.
APCu for local bins
// Requires APCu backend module
$settings['cache']['bins']['bootstrap'] = 'cache.backend.apcu';
- bootstrap: Keeps hot bootstrap data in process for lowest latency.
Runtime/server settings (outside settings.php)
PHP settings (php.ini)
OPcache
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=192
opcache.max_accelerated_files=16229
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.interned_strings_buffer=16
opcache.fast_shutdown=1
opcache.enable
: Turns OPcache on for FPM or Apache.opcache.enable_cli
: Keeps OPcache off for CLI.opcache.memory_consumption
: Allocates memory pool for compiled scripts.opcache.max_accelerated_files
: Sets hash table size.opcache.validate_timestamps
: Checks file timestamps for changes. Set to 0 for build-once deploys.opcache.revalidate_freq
: Sets seconds between timestamp checks whenvalidate_timestamps
= 1.opcache.interned_strings_buffer
: Allocates memory for shared strings.opcache.fast_shutdown
: Enables faster request shutdown.
APCu
apc.enabled=1
apc.enable_cli=0
apc.shm_size=128M
apc.ttl=0
apc.gc_ttl=3600
apc.enabled
: Turns APCu on for FPM.apc.enable_cli
: Keeps APCu off for CLI.apc.shm_size
: Sets total shared memory.apc.ttl
: Sets default TTL for entries.apc.gc_ttl
: Sets time to keep orphaned entries.
Redis server (redis.conf)
maxmemory 2gb
maxmemory-policy allkeys-lru
timeout 1
tcp-keepalive 60
maxmemory
: Sets memory cap.maxmemory-policy
: Sets eviction behavior when full.timeout
: Sets idle client timeout in seconds.tcp-keepalive
: Sets interval for keepalive probes.
Memcached server (flags)
memcached -m 2048 -I 4m -f 1.25 -o slab_reassign,slab_automove
-m
: Sets total memory in MB.-I
: Sets max item size.-f
: Sets growth factor for slab classes.-o slab_reassign,slab_automove
: Enables slab rebalancing.
Sizing quick rules
Cache | Key setting | Quick rule (MB) |
---|---|---|
OPcache | opcache.memory_consumption | MB = (codebase_MB × 3) + 32 |
OPcache | opcache.max_accelerated_files | ≈ 1.5 × PHP files (use 10000, 16229, 32531) |
APCu | apc.shm_size | MB ≈ (keys × (avg_item_bytes + 100) × 1.2) ÷ 1,000,000 |
Redis | maxmemory | MB ≈ (items × (avg_item_bytes + 50) × 1.3) ÷ 1,000,000 |
Memcached | -m | MB ≈ (items × avg_item_bytes × 1.3) ÷ 1,000,000 |
Memcached | -I | Start at 4 MB; increase if needed |
Common myths
- Myth: OPcache caches HTML — Truth: It caches compiled PHP code.
- Myth: APCu works across servers — Truth: It is local to one server process.
- Myth: Redis is always better than Memcached — Truth: Pick based on needs.
- Myth: Cache misses mean something is broken — Truth: Misses happen and warm up with traffic.
Quick setup checklist
- OPcache:
- Enable the extension in PHP.
- Tune memory size and revalidation settings for production.
- Ensure enough
opcache.memory_consumption
to hold your codebase.
- APCu:
- Install the PHP extension.
- Confirm CLI and FPM settings if you run both.
- Size
apc.shm_size
with headroom to avoid evictions.
- Redis:
- Install the server and PHP extension.
- Add the Drupal Redis module and map the right cache bins.
- Set client timeouts and consider sessions, locks, and queues.
- Memcached:
- Install the server and PHP extension.
- Add the Drupal Memcache module and map the bins you want.
- Set
-I
for max item size; ensure the app tolerates cache loss.
Avoid these traps
- Avoid mixing Redis and Memcached for the same bin.
- Avoid undersizing caches. Watch evictions and hit rate.
- Avoid over-caching. Focus on expensive, reusable data.
- Avoid breaking invalidation. Respect cache tags and contexts.
How to measure success
- Response time trends: Time to first byte should drop after warmup.
- Database load: Fewer queries per request and lower CPU on the database.
- Hit ratio: Track cache hit rates. If hit rates stay low, review bin mapping and TTLs.
- Error logs: Watch for connection errors or timeouts from Redis or Memcached.
Final thoughts
Start with OPcache, add APCu, then Redis or Memcached for shared bins. Keep it simple, measure results, and tune.