Moving Moodle's Application Cache to Redis: What Actually Changes on a Multi-Node Site
On multi-node Moodle, every web server rebuilds the same caches on local disk. Pointing MUC's application store at Redis shares that work — here's the config, the mapping strategy, and the eviction-policy traps.
29 Jul 2026, 15:37 UTC

If you run Moodle behind a load balancer with several web nodes, you've probably noticed something odd: each node quietly rebuilds the same cache data on its own local disk. The first request on node A regenerates the course modinfo cache; the first request on node B does the exact same work again, hitting the database a second time. Multiply that across every cache definition and every node, and you're paying for redundant database queries that exist purely because the cache isn't shared.
The fix is well-supported: point Moodle's Universal Cache (MUC) at a shared Redis instance so all web nodes read and write one cache. This post covers what MUC actually is, a concrete configuration, and the operational trade‑offs that come with it.
How MUC decides where your cache lives
MUC is Moodle's caching abstraction layer. It splits cached data into three stores: application (shared, long‑lived data like plugin metadata, language strings, and course modinfo), session (per‑user state), and request (per‑request, in‑memory only). Each store can be backed by a different engine — filesystem, Memcached, Redis, and others.
Out of the box, the application store uses the filesystem inside moodledata. That's fine for a single server. On a cluster it's the worst of both worlds: every node keeps its own copy, and invalidations only propagate through the shared filesystem (if moodledata is even shared) or not at all. Redis gives you a single network‑visible cache, so one node's cache‑warming work benefits every node, and invalidations are consistent.
A worked configuration
You need two things before touching Moodle: a running Redis server reachable from all web nodes, and the phpredis PHP extension installed on each node (php -m | grep redis to check; install via your distro's php-redis package or PECL).
Then, as a site administrator, go to Site administration > Plugins > Caching > Configuration. Add a Redis store instance, giving it the server host and port (e.g., redis.internal:6379). Once the store exists, edit the mapping so the Application store uses your Redis instance instead of the default file store. Exact labels and paths vary slightly between Moodle versions, so confirm against the version you run.
You can also do this in config.php (owned by the web server user, edited on every web node) for infrastructure‑as‑code deployments:
$CFG->alternative_cache_factory_class = 'tool_cachestore_custom_factory';\n// Store instances and mappings are typically defined via the admin UI;\n// config.php overrides vary by version — check admin/tool/cache documentation\n// for your release before relying on file‑based definitions.In practice, most sites define the store through the admin UI and keep config.php minimal. Don't copy config snippets from a blog (including this one) without checking your version's docs.
Map hot caches to Redis, leave cold ones alone
MUC's underused feature is per‑definition mapping. On the same configuration page, you can route individual cache definitions — language strings, course modinfo, config — to specific stores. A sensible pattern: put frequently invalidated, frequently read definitions (modinfo, strings) on Redis, and leave rarely‑changing, bulky definitions on disk. This keeps Redis memory predictable and avoids evicting something expensive to rebuild.
The trade‑offs nobody should skip
Redis becomes a hard dependency. If Redis is unreachable and you have no failover, Moodle degrades or errors. Test this in staging: stop Redis briefly and confirm your monitoring alerts fire and you understand what users see.
Eviction policy matters. If Redis runs with volatile-lru or similar and fills up, it will silently drop cache entries. Moodle will rebuild them, but you lose the benefit and may see load spikes. Prefer noeviction with adequate memory headroom for the application cache.
Never put sessions in an evicting instance. If you also move session storage to Redis (a separate decision from MUC), an eviction logs users out mid‑session. Use a dedicated Redis instance or database‑backed sessions.
Measure, don't assume. Gains depend on workload. Enable Moodle's performance info in the footer (with debugging on, in a non‑production or low‑traffic window) and compare database query counts before and after. On the Redis side, redis-cli INFO keyspace confirms Moodle keys are being written, and MONITOR (briefly — it's expensive) shows live hits.
Closing
Shared application cache is one of the cleaner wins in scaling Moodle: one Redis instance, one admin UI change, and your web nodes stop duplicating cache rebuilds. Start in staging, map only the application store first, verify with INFO keyspace and query counts, and decide on sessions separately. If your before/after numbers show no difference, that's a valid result too — it means your bottleneck is elsewhere.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.