Skip to content

Cache ​

Rendered sections are fragment-cached in published mode. Invalidation works by cache tag, so caching only happens on a taggable store — one whose driver extends Laravel's TaggableStore. On any other driver the tag probe fails and FilamentCraft transparently falls back to no-cache: pages render fresh, nothing breaks, and you get no speedup.

Taggable — caching worksNot taggable — silently uncached
redis, memcached, apc, arrayfile, database, dynamodb

file is Laravel's default, so out of the box you get no fragment caching until you point this at a taggable store.

php
'cache' => [
    'enabled' => true,
    'store' => null,     // shipped default: the app's default cache store
    'ttl' => 3600,       // fragment lifetime in seconds
    'tag_prefix' => 'fc',
],

'store' => null (the shipped default) uses the application's default cache store. If that isn't a taggable one, point this at a store that is — for example 'store' => 'redis'.

Draft renders are never fragment-cached: the editor re-renders from the DraftStore on every request, so what you see is always current. (The DraftStore is itself cache-backed, keyed per user and template — it just isn't part of the fragment cache.)

Invalidation is per site ​

Every cached fragment is tagged site:{id}. Publishing a template or region — or saving site settings — flushes that one tag, which evicts all cached fragments for the site; there is no per-template granularity. Invalidation is wrapped in a try/catch, so a cache hiccup never blocks a publish.

Opting a section out: cacheable() ​

The render path checks YourSection::cacheable() before touching the cache; return false for sections whose output depends on per-request state:

php
public static function cacheable(): bool
{
    return false;
}

Built-ins that opt out: Countdown (the remaining time and expired state are computed server-side at render time), the commerce sections (Cart, Checkout, ProductListing, ProductDetail), and Header — but only while a custom localeUrlsUsing() resolver is registered, because host locale URLs are path-dependent and the fragment cache is per locale, not per path.

Cache-key composition ​

A fragment's key hashes the section's settings and blocks, plus the render color scheme and render context, and appends the locale and the site's theme version:

{tag_prefix}:section:{siteId}:{sectionId}:{sha1(settings+blocks+scheme+context)}:{locale}:{themeVersion}

That composition is the "why didn't my change appear" explainer: any settings edit, locale, theme-token change (theme version bumps), or color-scheme switch produces a new key automatically — stale output within the TTL can only come from data the key doesn't see (e.g. an external API a section reads at render time).

tag_prefix prefixes the key, not the tags

tag_prefix namespaces the cache keys so several apps can share one Redis instance. The invalidation tag is always site:{id}, unprefixed — if two apps share a store and a site id, flushes cross over; give them separate Redis databases instead.

What else FilamentCraft writes to this store ​

One thing besides fragments, and it is deliberately kept in the same store so it lands beside them rather than in whatever the app happens to default to: the section failure log.

When a section throws on a published page it is dropped rather than breaking the page, and the failure is recorded per site — section type, message, count, timestamp — so the editor can warn you once when you next open it and filamentcraft:doctor can list it. Entries expire after seven days, and are cleared the moment the editor has shown them (a still-broken section re-arms itself on the next public render).

It is not tagged, so it survives a publish flush, and every read and write swallows its own errors: a cache outage must never turn a broken section into a broken page. See Custom sections for the filamentcraft.rendering.show_errors knob, if you would rather a staging site render the failure card publicly than leave a hole.