MODX Caching Decision Guide: Cached vs Uncached Template Tags for Dynamic Content
Decide when to use cached MODX template tags versus uncached tags for dynamic content. Avoid stale user data and cache poisoning with a practical validation pattern.
17 Sept 2026, 08:24 UTC

Dynamic content in MODX often breaks when a resource is cached: a personalized greeting shows the wrong user, or a form token disappears. The useful takeaway is to keep the page shell cached and isolate request-dependent output in uncached tags.
Decision and constraints
In MODX Revolution, template tags come in two caching modes. A cached tag such as [[Snippet]] or [[$Chunk]] is parsed once and its output is stored with the resource cache. An uncached tag such as [[!Snippet]] or [[!$Chunk]] is evaluated on every request and is never stored.
Default to cached output for content that is identical for every visitor. Use uncached tags only when the output must vary by request, user, session, context, or time. Typical constraints that force uncached evaluation include personalized greetings, cart or form state, permission-dependent fragments, and anything that must not be stored in the resource cache.
Comparing supported tag types
| Tag form | What it returns | Caching behavior | Primary risk |
|---|---|---|---|
[[Snippet]] | Snippet output | Stored with resource cache | Stale or wrong for user-specific data |
[[!Snippet]] | Snippet output | Evaluated each request, not stored | Per-request DB/CPU cost; cache leakage if it sets placeholders used by cached tags |
[[$Chunk]] | Chunk output | Stored with resource cache | Same as cached snippet |
[[!$Chunk]] | Chunk output | Evaluated each request, not stored | Same as uncached snippet |
[[*field]] | Resource field or TV value | Follows resource cache and TV output rendering | Stale if resource cache is not cleared after edits |
[[~id]] | URL generation | Usually cheap; verify context and language behavior | Context or language misconfiguration |
Trade-offs that matter
Cached tags minimize database queries and keep the cache coherent, but request-dependent logic becomes stale or incorrect. Uncached tags restore correctness for personalization at the cost of per-request work. The most dangerous failure mode is cache poisoning: an uncached snippet calls setPlaceholder with a per-user value, and a later cached tag consumes that placeholder. The first request stores the personalized value in the shared resource cache, and subsequent visitors receive the leaked data.
Prefer isolating personalization in uncached tags or excluding the resource from caching rather than mixing the two. A common safe pattern is to keep the page shell cached and make only the personalized fragment uncached.
Concrete implementation pattern
Assume a template with a cached header, content area, and footer, plus a user panel that must reflect the current session.
[[$header]]
[[*content]]
[[!$userPanel]]
[[$footer]]
If the fragment needs data, have its snippet return a string directly or call an uncached chunk. Do not set a placeholder in the uncached snippet and then render [[placeholder]] from a cached chunk.
<?php
// Snippet: userPanelData
// Return a string; do not call $modx->setPlaceholder()
// for values consumed by cached tags.
$user = $modx->user->get('username');
return 'Hello, ' . ($user ? $user : 'guest');
?>
Then render it with an uncached chunk:
<div class="user-panel">[[!userPanelData]]</div>
Validation pattern
To confirm cache behavior on a cacheable resource, add a test snippet that returns a per-request marker. In the MODX manager, go to Elements > Snippets and create a snippet named testMarker with the required element-management permissions.
<?php
return 'marker-' . time();
?>
On a cacheable resource, call the snippet twice in the template:
Cached: [[testMarker]]
Uncached: [[!testMarker]]
Clear the site cache, then request the page twice as a guest. The cached call should remain constant across both requests until the cache is cleared. The uncached call should change on each request. Repeat the test as an authenticated user to ensure personalized fragments are uncached and isolated.
Expected check: View the rendered HTML source and compare the two marker strings between requests. If the cached marker changes without a cache clear, the resource or tag is not being cached as expected. If the uncached marker stays constant, the tag may be cached or the resource may be excluded from caching.
Limitations and version assumptions
MODX major versions and extras can change parser and cache behavior. The examples above assume core MODX Revolution tag syntax and the default parser. Confirm the exact system settings for your version, whether an element is core or an extra, and the plugin event names and APIs before relying on plugin-set placeholders. Manager preview or different contexts may not reflect public cache behavior; validate in the actual context and cache state.
Do not place expensive collection queries in uncached tags on high-traffic pages. Use a controlled cache refresh strategy instead. After changing templates or snippets, clear the cache before testing so stale output does not mask the result.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.