# How caching works

**Goal:** understand the two caches every Cloud Platform application sits behind, [Varnish](/start-here/glossary/#varnish) in front and [memcached](/start-here/glossary/#memcached) behind, well enough to predict what gets cached, control cache lifetime from Drupal, and enable memcached correctly.

Everything below is current-generation ([Cloud Next](/start-here/glossary/#cloud-next)) behavior. [Cloud Classic](/start-here/glossary/#cloud-classic) differs in a few details, each one linked to docs.acquia.com where it comes up.

## What you'll have when you're done

- A mental model of the request path and which layer answers which requests.
- The cacheability rules: why a given response is or isn't stored by Varnish, and for how long.
- Drupal configured to feed Varnish a sensible cache lifetime, and memcached enabled if your site benefits from it.

## Prerequisites

- A Cloud Platform application (see [ship code to environments](/cloud-platform/code-workflow/quickstart/) if you're new to the platform)

## Steps

Jump to a task:

- [Know the request path](#know-the-request-path)
- [Learn what Varnish will and won't cache](#learn-what-varnish-will-and-wont-cache)
- [Set the Varnish TTL from Drupal](#set-the-varnish-ttl-from-drupal)
- [Vary the cache on cookies, if you must](#vary-the-cache-on-cookies-if-you-must)
- [Enable memcached if your site benefits](#enable-memcached-if-your-site-benefits)

<Steps>

1. ### Know the request path

   <ConceptDiagram name="cache-layers" height={360} />

   A request that Varnish can answer never reaches PHP at all. A request that gets through runs your Drupal code, which in turn consults its own caches; with memcached enabled, most of those internal cache reads come from memory rather than the database. The two layers solve different problems: Varnish protects the whole stack from anonymous traffic, memcached makes the requests that do get through cheaper.

2. ### Learn what Varnish will and won't cache

   Varnish caches two kinds of responses:

   - **Anonymous page responses.** Full HTML responses to visitors without a session.
   - **Static assets** (images, JavaScript, CSS) for anonymous *and* authenticated visitors, as long as the assets aren't in Drupal's private file system. Files larger than 10 MB are never cached.

   Whether a specific response is stored comes down to a few rules:

   - **Only `GET` and `HEAD` requests** are cacheable. Any code answering `HEAD` requests can set a `Cache-Control` response header and Varnish respects it.
   - **Session cookies bypass the cache entirely.** A request whose `Cookie` header matches `S?SESS[a-zA-Z0-9]*`, `NO_CACHE`, or `PERSISTENT_LOGIN_*` is passed straight to Drupal, and its response is not stored. This is why a logged-in editor always sees fresh content. Requests carrying an `Authorization: Basic` header bypass the cache the same way.
   - **Static assets have cookies stripped.** Cookie headers, session ones included, are removed from asset requests so the assets stay cacheable even for logged-in users.
   - **Status codes:** responses of `302` and above are not cached, with one exception: `404`. Both `404` and `301` responses are cached for a minimum of 15 minutes regardless of what your application asks for, to blunt cache stampedes. A response header can opt a page out of that floor, but Acquia recommends against it; see [Varnish headers](https://docs.acquia.com/acquia-cloud-platform/varnish-headers) on docs.acquia.com.
   - **Lifetime comes from your headers.** How long a stored response lives is set by `Cache-Control: max-age` (or `s-maxage`, which wins when both are present). A missing, invalid, or negative `max-age` means the response isn't cached.

   Varnish configuration itself is Acquia-managed and shared; you steer it entirely through response headers. Custom Varnish configuration exists only for Cloud Platform Enterprise subscriptions with dedicated load balancers; to request it, ask your Acquia account manager, or [contact Acquia Support](https://acquia.my.site.com/s/contactsupport). Do not install the Varnish Drupal module: it expects direct load-balancer connections the platform doesn't provide.

3. ### Set the Varnish TTL from Drupal

   The single Drupal setting that drives Varnish is **Browser and proxy cache maximum age** on the Performance page (`/admin/config/development/performance`). It becomes the `max-age` in your responses' `Cache-Control` header, which is the lifetime Varnish uses. Set to *no caching*, Drupal sends `max-age=0` and nothing is stored; a reasonable production value is 6 to 12 hours. Long lifetimes are what make Varnish effective, and the [purge tooling](/cloud-platform/caching/stale-content/) is what makes long lifetimes safe when content changes.

4. ### Vary the cache on cookies, if you must

   The platform's Varnish ignores almost all cookies for cache-variation purposes. If your application serves different cacheable content based on a cookie, only these are usable:

   - Three generic cookies, `acquia_a`, `acquia_b`, and `acquia_c`, arrive at your application as `X-Acquia-Cookie-A/B/C` request headers.
   - One custom cookie prefixed `acquia_extract:` (for example `Cookie: acquia_extract:CART_ID=1234;`) arrives as `X-Acquia-Cookie-Key: CART_ID` plus `X-Acquia-Cookie-Value: 1234`.

   Respond with a `Vary` header naming the relevant `X-Acquia-Cookie-*` headers to store one cache object per value, or `Cache-Control: no-cache` to keep those responses out of the cache. Keep variations per response to roughly ten or fewer: varying on unpredictable values (user IDs, timestamps) fills the cache and defeats it. Details and worked examples are in [Cookies and Varnish](https://docs.acquia.com/acquia-cloud-platform/cookies-and-varnish) on docs.acquia.com.

5. ### Enable memcached if your site benefits

   With memcached enabled, most of Drupal's cache bins live in memory rather than in the database's `cache_*` tables, cutting database load on requests that reach PHP. Memcached is a cache in front of the database, not a replacement for it. The bookkeeping that tracks cache tag invalidations stays in the database, and so does any bin pinned there in settings. Everything memcached holds is a copy Drupal rebuilds if it is evicted. It helps most on large applications with heavy database activity; a small or already-fast site can actually get slower, so compare performance with it on and off before committing.

   On Cloud Next environments memcached is available by default with 64 MB allocated, adjustable per environment with `acli api:environments:update myapp.prod --memcached_limit='128' --task-wait`. Acquia recommends a mid-range 128 MB or 256 MB when the default runs short, and advises against exceeding 2048 MB, an allocation only the largest multisite deployments benefit from (and one that can incur fees on subscriptions with Cloud Capacity Unit limits). Allocation for both platform generations is detailed in [Configuring PHP settings](https://docs.acquia.com/acquia-cloud-platform/configuring-php-settings) on docs.acquia.com.

   To enable it for a site running the current Drupal version:

   1. Add the [Memcache API and Integration](https://www.drupal.org/project/memcache) module to your codebase:

      ```bash
      composer require drupal/memcache
      ```

   2. On Cloud Next, that's the whole wiring: the platform's included configuration both selects memcache as Drupal's cache backend and injects the connection settings (`memcache_servers`, `memcache_key_prefix`), so there is nothing to add to `settings.php`. Do not set those values yourself. Details are in [Enabling Memcached](https://docs.acquia.com/acquia-cloud-platform/enabling-memcached-cloud-platform) on docs.acquia.com.

   3. Rebuild caches:

      ```bash
      drush cr --uri=example.com
      ```

      then truncate the tables whose names start with `cache_` once. This clears out rows written before the switch, which the moved bins will never read again; it reclaims space, nothing more. Truncate rather than drop, and leave `cachetags` and every other table alone: bins still on the database keep using their tables, and Drupal repopulates a truncated cache table on demand.

   :::note
   On Cloud Next, non-production memcached storage may be emptied from time to time as Acquia optimizes those environments. Don't treat memcached as durable storage anywhere, and especially not on Dev or Stage.
   :::

</Steps>

## When something goes wrong

**A deployed change isn't showing**: work through [fix stale content](/cloud-platform/caching/stale-content/) step by step.

**Varnish suddenly stops caching anything**: almost always a module setting a session-like cookie for anonymous visitors; see the [cookie pitfalls](/cloud-platform/caching/stale-content/#when-something-goes-wrong).

**Memcached seems too small**: the Memcache Admin submodule's report (`Reports > Memcache statistics`) shows evictions; a high eviction rate relative to activity means the cache is thrashing and needs a bigger allocation.

## Next steps

- [Fix stale content](/cloud-platform/caching/stale-content/): diagnosis and purging when the cache holds the wrong thing.
- [Ship code to environments](/cloud-platform/code-workflow/guide/): where cache purging fits into a deploy (Cloud Hooks).
- [What the platform logs](/cloud-platform/observability/logs/): watching cache behavior in production.
