Documentation is English-only for now. The rest of the site follows your language.
Caching
jf-cache drivers, what is cached per site, headers, CDN purge, stats, clear, and the plugin cache API.
8 min read
Justflows ships jf-cache so hot paths skip the database. Redis is not required. Configure in .env or Tools → Performance suite. Full narrative: docs/CACHE.md in the platform repo.
Drivers
filesystem(default) — survives process restart; directoryCACHE_DIR.memory— per process only.redis— reserved; not implemented.CACHE_REDIS_URLis ignored for now.CACHE_ENABLED=0— always run the producer, never store.
Layers
| Prefix | What | Invalidated when |
|---|---|---|
page:html: | Full public HTML | Content, theme, menu, settings, CSS provider |
content: | Published items and alternates | Content save/delete |
theme:mods: | Customizer mods | Design/theme save |
menus: | Navigation | Menu edits |
css:provider: | Active framework assets | Provider activate/delete |
security-headers:config | Header policy | Security save (short TTL) |
Every key carries the site id, so one site is never served another's cached page. The filesystem driver writes each site's entries under .cache/<siteId>/. A publish clears that site's folder only, and removing a website removes it.
Preview (?preview) and logged-in editors bypass page cache. Responses may include X-Jf-Cache: hits=… and X-Jf-Page-Cache: HIT|MISS|BYPASS.
Unversioned public assets
Hand-authored scripts and styles under public/ (/js/site-nav.js, /js/site-chrome.js, …) are served with Cache-Control: no-cache rather than a day-long max-age: they sit at stable, unversioned URLs, so a long TTL pinned stale copies after an update. no-cache still keeps the file cached and revalidates cheaply against the ETag (304). Content-hashed admin bundles keep their long cache lifetime.
While browser cache is off (the default on a fresh install), public HTML pages send Cache-Control: no-cache and CDN-Cache-Control: no-store. A CDN in front of the site then does not hold pages, so a change in the admin, such as a new site icon, shows on the next request. Turn browser cache on under Tools → Performance suite to let browsers and the CDN keep pages for JF_BROWSER_CACHE_HTML_MAX_AGE seconds.
Cache-Control per content type and post
Admin → Content Types gives each cacheable type a Cache-Control setting: inherit the site default, never cache (private, no-store), or a validated custom header. A single post or page can override it under Advanced; the override follows drafts, revisions, and translations, and a published post keeps its live policy until the draft is published.
The order is: core privacy rules, then the post, then the content type, then the site default. Private and no-store policies bypass the shared page cache and deployed static pages and are left out of new exports; a public max-age also caps how long the page cache keeps the page. Saving a policy clears the page and content caches and purges the CDN. The built-in Account type is always private and has no override (migration 0046_content_type_cache_control).
CDN purge
When revalidation clears pages, content, menus, theme, CSS, or site context, Justflows also tells the CDN to drop that site's cached pages (https://<hostname>/* for every hostname of the site). Connect the CDN under Admin → Settings → CDN. A CDN failure is logged and never fails the save.
| Provider | Fields |
|---|---|
| Bunny.net | Account API key (required), pull zone ID (optional, for a full-zone purge) |
- The connection is saved on the platform site. The API key is encrypted with
APP_SECRET, never returned, and shown only by its last four characters. - Test connection checks the credentials. Purge this site clears the site at the CDN by hand. Turning the connection off keeps it without purging.
- A customer site in a multisite installation does not get the connection form. It can still purge its own hostnames through the platform connection.
- With no connection turned on, every site falls back to
BUNNY_API_KEYandBUNNY_PULL_ZONE_IDin.env. Without either, only the server cache is cleared.
Clear and inspect
- Tools → Clear cache now (no restart).
POST /api/cache/clear(administrator).justflows cache clear.GET /api/cache/statsand Tools → Object cache (hits, misses, hit rate, key count).- Site Health includes an object-cache check.
LOG_LEVEL=debuglogs HIT/MISS lines.
API for core and plugins
Preferred: remember(key, ttlSeconds, fn) — read-through with in-flight deduplication. Also get, set, delete, invalidate(prefix), clear. Plugins only see plugin:{id}: keys via ctx.cache.
const menu = await ctx.cache.remember("primary", 300, () => loadMenu());Selective revalidate: CACHE_REVALIDATE_ENABLED and CACHE_REVALIDATE_OBJECTS (pages, content, menus, theme, cssProviders, site). Action cache.revalidated fires when it completes. Related admin routes also exist under /api/performance/*.