Cache Configuration
The [cache] section controls PRISM's in-memory cache for rendered HTML. Caching avoids redundant renders and dramatically reduces response times for repeat requests.
TOML Example
[cache]
enabled = true
max_entries = 10000
max_memory_bytes = 268435456
default_ttl_secs = 3600
grace_period_secs = 300
strip_query_params = ["utm_*", "fbclid", "gclid", "msclkid", "_ga"]
error_ttl_secs = 30
skip_authenticated = true
synthesize_cache_control = true
honor_request_no_cache = false
[[cache.rules]]
pattern = "/blog/**"
ttl_secs = 86400
[[cache.rules]]
pattern = "/products/**"
ttl_secs = 7200
[[cache.rules]]
pattern = "/special-page"
ttl_secs = 60
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
enabled | Boolean | true | Enable or disable caching entirely |
max_entries | Integer | 10000 | Maximum number of cached pages |
max_memory_bytes | Integer | 268435456 (256 MiB) | Maximum memory for cached content |
default_ttl_secs | Integer | 3600 (1 hour) | Default time-to-live for cached entries |
grace_period_secs | Integer | 300 (5 minutes) | Serve stale content while revalidating in background |
rules | Array of {pattern, ttl_secs} | [] | Path-specific TTL overrides using glob patterns |
strip_query_params | Array of Strings | ["utm_*", "fbclid", "gclid", "msclkid", "_ga"] | Query parameters to strip from cache keys (supports globs) |
error_ttl_secs | Integer | 30 | TTL for caching error responses (status >= 500). 0 = do not cache errors |
skip_authenticated | Boolean | true | Send requests with an Authorization header or any cookie to the origin instead of rendering them (render-all) |
synthesize_cache_control | Boolean | true | Add Cache-Control header to rendered responses if origin did not provide one |
honor_no_transform | Boolean | false | Stop rendering a response whose origin sent Cache-Control: no-transform, serving it unchanged instead |
vary | Array of Strings | [] | Request headers that fragment the cache key AND are forwarded to Chrome during render. See vary below. |
honor_request_no_cache | Boolean | false | Re-render instead of serving a stored response when the request carries Cache-Control: no-cache. See honor_request_no_cache below. |
Detailed Explanation
max_memory_bytes
The default is 256 MiB (268435456 bytes). When this limit is reached, the least recently used entries are evicted. Size your allocation based on average page size and expected unique URLs.
grace_period_secs
When a cached entry expires, PRISM can still serve the stale version for up to grace_period_secs while triggering a background re-render. This prevents cache stampedes and ensures visitors never wait for a cold render.
Serving stale has to be permitted, though. Since 1.4.0 an entry whose origin sent must-revalidate, proxy-revalidate or s-maxage is excluded: those forbid serving a stale response, and s-maxage carries proxy-revalidate semantics for shared caches (RFC 9111 §5.2.2.10). Such entries expire outright instead of entering the window — the freshness the origin granted is kept in full, and only the extension is withheld.
A background re-render that comes back uncacheable also removes the entry it was refreshing, rather than leaving the old copy to be served for the rest of the window.
rules
TTL rules are evaluated in order; the first matching glob pattern wins. If no rule matches, default_ttl_secs is used.
[[cache.rules]]
pattern = "/blog/**"
ttl_secs = 86400 # Blog posts: 24 hours
[[cache.rules]]
pattern = "/products/**"
ttl_secs = 7200 # Product pages: 2 hours
Place more specific patterns before broader ones, since the first match wins.
strip_query_params
Marketing and analytics query parameters are stripped from cache keys to avoid duplicate cache entries for the same page. Supports glob patterns (e.g., utm_* matches utm_source, utm_medium, utm_campaign, etc.).
skip_authenticated
In render-all mode, requests carrying an Authorization header or any cookie are sent straight to the origin rather than rendered.
Chrome renders with no session, so the render has no cart, no account and no per-customer pricing. Keeping that result out of the cache is not enough on its own — it stops one shopper's page reaching another, but the shopper who asked still receives the anonymous render. So these requests bypass rendering entirely.
In bot-only mode a human is already bypassed for being human; there this keeps a cookie-bearing crawler's render out of the shared cache.
An edge cache in front of PRISM needs its own rule: it may answer an authenticated request from a previously cached anonymous copy before PRISM ever sees it. Bypass edge caching for session cookies and Authorization.
synthesize_cache_control
When the origin does not include a Cache-Control header, PRISM adds one based on the configured TTL for that path. This helps downstream CDNs and browser caches respect PRISM's caching strategy.
error_ttl_secs
Error responses (HTTP 500+) are cached for a shorter duration to avoid serving errors for extended periods while still providing some protection against repeated failing renders. Set to 0 to disable error caching entirely.
Since 1.5.3 this setting governs both ends: the Cache-Control PRISM sends downstream announces this lifetime too, so a CDN in front holds the error for as long as PRISM does and no longer. At 0 the response is announced no-store.
It does not apply to 401, 403, 407 or 429 — those are not stored at all unless the origin states a lifetime of its own. See status codes.
honor_no_transform
RFC 9111 §5.2.2.6 tells an intermediary not to transform a representation, and replacing a shell with rendered HTML is exactly that transformation. PRISM does not obey it by default, which is a deliberate departure worth explaining rather than hiding.
The directive exists to stop intermediaries the origin does not control —
a carrier proxy recompressing images, a transcoding gateway. PRISM is not one
of those: your own operator installs it, points it at your own site, and pays
for precisely the transformation it performs. Magento and several other stacks
also emit no-transform inside a boilerplate Cache-Control with no intention
about rendering at all.
The failure modes decide the default. Obeying automatically would mean an upgrade silently stops rendering for someone who bought PRISM to render, with the symptom appearing weeks later as "our SEO stopped working" and no obvious cause. Not obeying violates the letter of a directive in a way nobody observes. The second is the cheaper mistake.
It is a visible choice, not an omission: prism_no_transform_ignored_total
counts every response this affects, whatever the setting. If it is non-zero
and you care about the letter of the spec, turn this on.
With it on, such a response is fetched from the origin and served unchanged,
marked x-prism-fallback: no-transform. Note that no-transform says nothing
about storing — an origin that sends it with a lifetime still wants the
response cached, and PRISM still caches it.
vary
Use vary when the same path produces different rendered HTML depending on a request header — most commonly Accept-Language for multilingual SSR.
When configured, PRISM does two things for every header in the list:
- Fragments the cache key so that requests differing only in the header value are stored as separate cache entries.
- Forwards the header value to Chrome via
setExtraHTTPHeadersso the SSR can actually produce variant-specific HTML. Without this, vary would just multiply identical cache entries — so PRISM does both atomically.
[cache]
vary = ["accept-language"]
Header names are case-insensitive. Header values are used as raw strings — en-US and en-us are stored as different variants. Pre-normalize at your CDN or reverse proxy to avoid cache fragmentation; for example, collapse the browser default Accept-Language: en-US,en;q=0.9 to a single primary tag like en before forwarding to PRISM.
Default is empty ([]) — no vary, one cache entry per path. Leave it empty for single-language sites.
:::tip Why not vary on every header by default?
Each unique combination of vary values multiplies the cache footprint. Defaulting to vary on, say, Accept-Language would explode cache size for sites that don't actually serve language-varied HTML. Better to opt in.
:::
:::warning Vary headers and bot/CDN behavior
Bots typically don't send Accept-Language, so they all share one variant — fine for SEO. But CDN caches in front of PRISM must also vary on the same header, or they'll serve the wrong language. Configure Vary: Accept-Language on your CDN to match.
:::
Example Use Cases
E-commerce site with mixed content freshness
[cache]
enabled = true
max_entries = 50000
max_memory_bytes = 536870912 # 512 MiB
default_ttl_secs = 1800
[[cache.rules]]
pattern = "/products/**"
ttl_secs = 3600
[[cache.rules]]
pattern = "/categories/**"
ttl_secs = 7200
[[cache.rules]]
pattern = "/blog/**"
ttl_secs = 86400
Development / debugging with caching disabled
[cache]
enabled = false
Aggressive caching for mostly-static site
[cache]
enabled = true
max_entries = 100000
default_ttl_secs = 86400
grace_period_secs = 3600
error_ttl_secs = 60
honor_request_no_cache
RFC 9111 §5.2.1.4 says a request carrying Cache-Control: no-cache must not be
served a stored response without revalidation. PRISM ignores that header by
default, and the default is deliberate.
PRISM is a shared cache, usually reachable from the public internet, and a revalidation costs a full Chrome render. Honouring the header unconditionally means one header, repeated, forces unbounded renders — a cache-busting denial of service that needs no credentials and no volume.
Enable it only where the listener is reachable from callers you trust:
[cache]
honor_request_no_cache = true
Recognised on requests:
Cache-Control: no-cacheCache-Control: max-age=0Pragma: no-cache— the HTTP/1.0 spelling, still sent by several browsers on a forced reload
Directives are matched as whole comma-separated tokens, so no-cache-extension
does not trigger it.
When enabled, the fresh render is stored, not discarded. no-cache in a
request forbids reusing a stored response, not storing the new one, so the
re-render refreshes the entry that every later request sees. The revalidating
request is reported as X-Prism-Cache: MISS.
If you sit behind a CDN, strip Cache-Control and Pragma from client requests
at the edge before enabling this, or the protection is only as good as the CDN's
own behaviour.