La documentation est uniquement en anglais pour le moment. Le reste du site suit votre langue.
Caching
jf-cache drivers, shared plugin cache stores, what is cached per site, headers, CDN purge, stats, clear, and the plugin cache API.
8 minutes de lecture
Justflows ships jf-cache so hot paths skip the database. Redis is not required; a plugin can add a shared store such as Redis when several processes must share the cache. 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.plugin:<pluginId>.<storeId>— a plugin cache store, shared by every process. Core ships no external driver; an unknownCACHE_DRIVERfalls back tofilesystem. The oldredisvalue andCACHE_REDIS_URLwere removed in 0.4.2.CACHE_ENABLED=0— always run the producer, never store.
Plugin cache stores
From Justflows 0.4.2, a plugin activated on the main site can offer a store that every process shares, so entries and invalidations reach every worker or machine. Pick it under Tools → Performance suite → Driver, or set CACHE_DRIVER=plugin:<pluginId>.<storeId> in every process's .env. Every process must use the same driver and store settings, which the plugin reads from its own configuration. Tools, Site Health, and Diagnostics show the store's status.
| Situation | What happens |
|---|---|
| Before the store is registered (startup) | The cache is bypassed: reads miss and writes are skipped. |
| Plugin inactive, or active only on another site | Bypassed, shown as Unavailable in Tools and as a Site Health warning. |
| The store cannot be configured | Bypassed, with the plugin's message in Tools and Diagnostics. |
| A read fails or takes longer than 2 s | That read is a miss. |
| A write fails | That write is skipped. |
| A delete, invalidate, or clear fails | Bypassed until a full clear of the store succeeds (retried at most every 5 s), so no process serves an entry whose invalidation was lost. |
Pages keep rendering during an outage; they are just not cached. After switching away from a plugin store and back, use Clear cache now.
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. ctx.cache.registerStore({ id, label, create }) offers a backend for the whole cache (needs the cache:store permission, main site only, SDK 0.1.9); see Plugins.
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/*.