Skip to main content

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​

ParameterTypeDefaultDescription
enabledBooleantrueEnable or disable caching entirely
max_entriesInteger10000Maximum number of cached pages
max_memory_bytesInteger268435456 (256 MiB)Maximum memory for cached content
default_ttl_secsInteger3600 (1 hour)Default time-to-live for cached entries
grace_period_secsInteger300 (5 minutes)Serve stale content while revalidating in background
rulesArray of {pattern, ttl_secs}[]Path-specific TTL overrides using glob patterns
strip_query_paramsArray of Strings["utm_*", "fbclid", "gclid", "msclkid", "_ga"]Query parameters to strip from cache keys (supports globs)
error_ttl_secsInteger30TTL for caching error responses (status >= 500). 0 = do not cache errors
skip_authenticatedBooleantrueSend requests with an Authorization header or any cookie to the origin instead of rendering them (render-all)
synthesize_cache_controlBooleantrueAdd Cache-Control header to rendered responses if origin did not provide one
honor_no_transformBooleanfalseStop rendering a response whose origin sent Cache-Control: no-transform, serving it unchanged instead
varyArray of Strings[]Request headers that fragment the cache key AND are forwarded to Chrome during render. See vary below.
honor_request_no_cacheBooleanfalseRe-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:

  1. Fragments the cache key so that requests differing only in the header value are stored as separate cache entries.
  2. Forwards the header value to Chrome via setExtraHTTPHeaders so 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-cache
  • Cache-Control: max-age=0
  • Pragma: 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.