Full-page cache

On this page 7

A full-page cache is a server-side cache that stores the complete rendered HTML response of a page and returns that stored copy to later visitors, so the application code, template engine and database queries do not run again for each request. In server performance it is usually the single most effective way to cut response time and raise requests per second for content that many visitors see in the same form.

The cache can live in the web server, in a dedicated reverse proxy such as Varnish, in an application plugin, or at a CDN edge. Wherever it sits, the principle is the same: render once, serve many times until the content changes or the stored copy expires.

How a full-page cache serves requests

Each incoming request is turned into a cache key, normally built from the host, the path, the query string and sometimes selected headers such as the device type or language. If a valid entry exists for that key, the cache returns a hit directly, often in under a millisecond from memory. If not, the request is a miss: it goes to the application, and the response is stored for the next visitor.

Freshness is governed by a time to live (TTL) and by invalidation. A TTL lets an entry expire after a set period, while invalidation, also called purging, removes specific entries the moment content changes. Many systems also support stale-while-revalidate, which serves an expired copy briefly while a fresh one is generated in the background.

The table below summarizes the main parameters that control a full-page cache and their typical ranges.

ParameterTypical rangeEffect
TTL for HTML1 minute to 24 hoursLonger TTL raises hit ratio but risks stale pages
Cache keyHost, path, query, selected headersMore variation means more entries and fewer hits
Grace or stale periodSeconds to hoursKeeps serving during regeneration or backend failure
Storage sizeHundreds of MB to several GBToo small causes evictions of popular pages
Bypass rulesCookies, logged-in users, POSTPrevents caching of personal or unsafe responses
Key parameters of a full-page cache

Where the full-page cache can sit

The location of the cache decides how much work a hit avoids and who controls invalidation. A cache closer to the visitor saves more network distance, while a cache inside the application understands content changes best.

PlacementExampleStrengthWeakness
Application pluginCache written to disk by a CMS pluginEasy setup, aware of content changesPHP or the app may still start
Web server moduleNginx FastCGI cacheSkips the application entirelyPurging needs extra tooling
Reverse proxyVarnish in front of the serverVery fast, flexible rules in VCLExtra layer to operate
CDN edgeEdge cache with HTML rulesServes from locations near visitorsPurge propagation takes time
Placement options for full-page caching

Layers can be combined. A common design uses a CDN edge for anonymous visitors and a local proxy or server cache as a second tier, so a miss at the edge still avoids rendering in most cases.

Full-page cache compared with other caching layers

A full-page cache works at the coarsest granularity: the whole response. Other server-side caching layers store smaller pieces and still require the application to assemble the page, which makes them complementary rather than competing.

LayerWhat it storesWork still done on a hit
Full-page cacheEntire HTML responseAlmost none
Object cacheQuery results and computed objectsTemplate rendering and application logic
OPcacheCompiled PHP bytecodeExecuting code and running queries
Browser cacheResponses on the visitor deviceNone, but only for that visitor
Caching layers on a typical web server

Because an object cache and OPcache speed up misses and uncacheable requests, they remain valuable even with a strong full-page cache. Logged-in dashboards, carts and search results often bypass the page cache and depend on those lower layers and on the size of the PHP worker pool.

Configuring the cache for dynamic sites

The hardest part of full-page caching is deciding what must never be cached. Any response that contains personal data, a session-specific token or a cart total must bypass the cache or be split so that the personal part loads separately.

Request typeRecommended handlingReason
Anonymous article or product pageCache with long TTL and purge on updateSame for every visitor
Home and category pagesCache with shorter TTLChange often as content is added
Logged-in pagesBypass by session cookieContain personal data
Cart, checkout, accountNever cachePer-user state and security tokens
Pages with small personal blocksCache shell, load blocks via JavaScript or ESIKeeps most of the page cacheable
Decisions for common request types

Cache warming after a deployment or a full purge prevents the first visitors from all hitting a cold cache at once. Request coalescing, where the cache sends only one request to the backend per missing key, protects the server from a cache stampede on popular pages.

Pitfalls and failure modes

  • Leaking personal content: caching a page rendered for a logged-in user and serving it to everyone is the most serious failure.
  • Cookie noise: analytics or consent cookies that vary per visitor can make every request a miss if the cache treats all cookies as significant.
  • Query string variation: tracking parameters create thousands of keys for the same page unless they are stripped or ignored.
  • Stale content after edits when purging is not tied to publishing events.
  • False confidence in benchmarks: a test that hits only cached URLs hides how slow uncached pages remain.

A useful health metric is the hit ratio for HTML. Content sites commonly reach high ratios for anonymous traffic, while shops with many personalized pages see much lower values; tracking the trend matters more than any single target.

A non-technical view

Building a web page takes work. The server reads the database, fills in a template and assembles the result. A full-page cache keeps a finished copy of the page after the first visit. The next visitors get that copy right away.

It is like a bakery that bakes a tray of bread in the morning instead of baking one loaf per customer. Most people get fresh bread instantly. Special orders, like a cake with your name on it, are still made individually.

A concrete example

A regional news site on a single server handles about 40 requests per second on normal days, with each article taking around 400 milliseconds to render. When a story goes viral, traffic jumps to several hundred requests per second, the PHP worker pool fills up and visitors start seeing timeouts.

The team adds an Nginx FastCGI cache for anonymous visitors, with a five-minute TTL, a bypass for the login cookie and a purge triggered whenever an editor updates an article. During the next traffic spike, the HTML hit ratio stays high, cached articles are served in a few milliseconds, and the backend load barely changes because almost every request is answered from the cache.