Running a site

Caching and performance

The page cache

Public pages change only when something is published, so Gansey keeps each rendered page in memory, by path (and by language prefix, when a module serves the site under prefixes). The first request for a page renders it, passes it through any modules listening on page.html and response.headers, and stores the result; later requests are served from memory until the cache is dropped. Only successful HTML responses are stored. The cache lives in the process, so it starts empty on every restart and is not shared between processes.

The whole cache is dropped when:

  • a page, entry, site part or the theme is published, unpublished or deleted, including a scheduled publish;
  • a content type, taxonomy or term is created, changed or deleted;
  • site settings change in Settings → Site;
  • a module is installed, removed, reloaded, switched on or off, or its files change on disk;
  • a module writes content, changes the cache policy or language prefixes, or clears the cache itself;
  • the optimise queue finishes new image copies.

Search results, previews and module routes are never cached.

ETags and revalidation

Every cached page carries a strong ETag taken from a hash of its HTML. A browser or proxy that sends it back in If-None-Match gets 304 Not Modified with no body, so checking a page that has not changed costs almost nothing. The bundled assets and the admin's files carry ETags too.

Cache headers

WhatCache-Control
cached public pagespublic, max-age=0, must-revalidate, or the policy's page lifetime
pages the policy leaves out of the cacheprivate, no-cache
search, previews, module pages in the site chromeprivate, no-store
bundled assets under /_gansey/assets/no-cache, or the policy's asset lifetime
media under /media/public, max-age=31536000, immutable
the admin's built files under /admin/assets/public, max-age=31536000, immutable
robots.txtpublic, max-age=300

Media files can be kept for a year because every address includes the item's id, and next-generation copies are named after their content, so a changed file always gets a new address. Bundled assets keep the same address from one release to the next, so by default browsers revalidate them.

Pages outside production also carry X-Robots-Tag: noindex, nofollow (see Security).

The cache policy

A module with the cache permission can set the site's cache policy with ctx.cache.configure:

ctx.cache.configure({ exclude: ["/account", "/shop/*"], page_max_age: 0, asset_max_age: 86400 })
  • exclude lists paths rendered afresh on every request and never stored. /account matches that path only; /shop/* matches /shop and everything under it.
  • page_max_age is how many seconds browsers may reuse a page without asking again. 0, the default, means they ask every time, which the ETag keeps cheap.
  • asset_max_age does the same for the bundled assets.

Lifetimes are capped at a year. The policy applies only while the module that set it is running: switch that module off and the defaults return. Modules can also add response headers to pages, limited to caching, resource-hint and security-policy headers and anything starting x-. See Modules for the details.

The performance module

The official performance module (gansey-module-performance) is the usual way to tune all this from the admin. It chooses which next-generation image formats the media library makes and optimises new uploads, sets the page cache exclusions and browser cache lifetimes, minifies HTML, gives each page's first image priority, and runs page speed audits on demand or on a schedule, keeping their history. The audits call an external page speed audit service, which the module declares in its manifest. Install it from the registry or from its folder:

gansey mod add performance
gansey mod add ../modules/performance    # from a checkout

Its settings apply only while it runs. Without it, core makes WebP copies at quality 80 when asked and uses the default cache headers above.