Leveraging MODX Revolution’s Built‑In Caching to Cut Page Load Times
Discover how to turn on MODX Revolution’s resource caching, set lifetimes, test gains with DevTools, and keep dynamic snippets fresh to improve site speed.
24 Dec 2025, 08:13 UTC

Problem: Repeated Database Hits Slow Down a MODX Site
On a MODX Revolution site with many visitors, each page request can trigger dozens of database queries and snippet executions. When the content does not change on every request, this repeated work is wasted and increases the Time to First Byte (TTFB). The solution is to let MODX serve a pre‑rendered page from cache whenever possible.
How MODX Handles Caching
MODX Revolution offers a single, flexible cache manager that stores two kinds of data:
- Resource cache – the entire rendered HTML of a Resource (page) after all Snippets, Chunks, and output filters have run. A cached Resource is served directly to the browser, bypassing the PHP engine and database for that request.
- Cache API objects – any data explicitly stored with
$modx->cacheManager, such as custom snippets that call$modx->cacheManager->get()orset(). This is not a separate “snippet cache” layer; it is simply a way to persist expensive data across requests.
Both are controlled by system settings. The most important ones are:
| Setting | What It Controls | Typical Value |
|---|---|---|
| cache_enabled | Turn the whole cache system on or off. | Yes (default) |
| cache_default | Default lifetime in seconds for cached Resources that do not override it. | 0 – never expires until cleared. |
| cache_automatic_refresh | If Yes, MODX will try to refresh an expired cache entry the next time it is requested. | Yes |
| cache_db | When Yes, cached data is stored in the modx_cache database table. When No, files are written under core/cache/. | No (file cache is the default) |
In MODX 3.x the setting names are the same but appear under the cache namespace (e.g., cache.enabled). Always confirm the names in the System Settings grid for your version.
Worked Example: Cache a Blog Container for 15 Minutes
Log in to the Manager and open System → System Settings. Filter for
cache_enabledand set it to Yes if it isn’t already.Find
cache_defaultand change it to 900 (15 minutes). This applies to any Resource that doesn’t specify its own lifetime.Decide on storage: keep
cache_dbset to No to use the file system, which is usually faster for most shared hosting setups.Open the Blog container Resource (or any parent Resource) for editing. In the Settings tab, make sure Cacheable is checked. Optionally set Cache Expires to a different value if you need a shorter or longer lifetime for that page.
Save the Resource.
Verify the change in the browser. Open
https://your-site.com/blogin Chrome, press F12 to open DevTools, go to the Network tab, and uncheck Disable cache (so the browser can use the server cache). Reload the page twice:- First load – the Time column shows the full server processing time.
- Second load – the Time column should be lower, indicating that the server served the cached page.
On the server, navigate to
core/cache/resource/(or the configured cache directory). You should see a file named something likeresource_123.cache.phpwith a timestamp within the last 15 minutes.
Ensuring Dynamic Snippets Stay Fresh
Any snippet that outputs user‑specific data (e.g., the logged‑in user’s name, current time, or shopping cart contents) must bypass the cache. The syntax to force an uncached call is simply:
[[!UserGreeting]]
The exclamation mark after the opening brackets tells MODX to skip both resource caching and any cache API calls made within that snippet. Do not use a non‑existent [[!uncached]] tag; that syntax will be parsed as a normal snippet call.
If you need to cache expensive data inside a snippet but still want fresh output for certain parameters, use $modx->cacheManager directly:
$key = 'user_' . $modx->user->get('id');
$data = $modx->cacheManager->get($key);
if ($data === false) {
// expensive calculation
$data = date('Y-m-d H:i:s');
$modx->cacheManager->set($key, $data, 3600); // cache for 1 hour
}
return $data;
Trade‑offs and Limitations
- Stale Content – Cached pages will not reflect changes until the lifetime expires or the cache is cleared. For frequently updated sections, consider disabling Cacheable or setting a very short lifetime.
- Personalized Data – Any snippet that relies on the current user must be marked
[[!SnippetName]]or use the cache API with a unique key per user. - Database Cache – Enabling
cache_dbcan increase database load and may be slower than file caching on some hosts. Use file caching unless you have a specific need for database storage.
Practical Actions to Finish
Enable
cache_enabledglobally and setcache_defaultto a sensible value (e.g., 900 seconds for static pages).For each context that hosts frequently changing content, override
cache_defaultin the context settings or set Cache Expires on individual Resources.Mark dynamic snippets with the
[[!SnippetName]]syntax or use the cache API with per‑user keys.Schedule a nightly cache purge if you rely on short lifetimes. A simple cron entry can call the Manager’s CLI tool (example for 2.x):
php /path/to/modx/cli/clear-cache.phpFor 3.x, use the new
modx cache:clearcommand if you have the Composer‑based CLI installed.After any change, re‑check the Network tab in DevTools and the Reports → Cache page (or
core/cache/directory) to confirm that new cache entries are created and old ones are removed as expected.
Conclusion
Enabling MODX Revolution’s caching is a low‑cost, high‑impact way to reduce server load and improve page speed. By setting a reasonable default lifetime, ensuring dynamic snippets stay uncached, and monitoring the cache, you can keep your site fast without sacrificing freshness.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.