FastCGI Cache, Varnish, or Application Cache: Which Layer for a PHP Site

- Should a PHP site use FastCGI cache, Varnish, or an application cache?
- What does each cache actually store?
- When is Nginx FastCGI cache the simplest fit?
- When does Varnish earn the extra layer?
- When is an application or object cache the right layer?
- Can you combine these caching layers?
- How does TLS affect the decision?
- Which cache should you choose first?
- Sources
Should a PHP site use FastCGI cache, Varnish, or an application cache?
Use FastCGI cache when Nginx already fronts a mostly public PHP site and you need full-response caching without another daemon. Add Varnish when its HTTP cache policy and operational tooling justify another proxy layer. Use an application or object cache when the expensive work is inside PHP or database queries and responses must remain personalized. These layers solve different problems; a site may use more than one, but each added cache needs an owner, invalidation rules, observability, and a safe bypass.
This is a capability and operational-cost comparison, not a benchmark. No universal hit rate, latency improvement, or traffic multiple is claimed.
What does each cache actually store?
A full-page cache stores an HTTP response under a cache key. On a hit, it can avoid running PHP and repeating the database work that produced the page. Nginx FastCGI cache and Varnish both operate at this response layer, although they occupy different positions and use different configuration models.
An application cache stores values chosen by the application: a database-query result, computed object, rendered fragment, session-independent lookup, or other reusable data. PHP still runs, but it may skip the expensive operation. WordPress, for example, documents its object cache as a way to save trips to the database. Its default cache lasts only for the request unless a persistent cache implementation is installed.
| Layer | Primary cached unit | Can bypass PHP on a hit? | Main control plane | Added service? |
|---|---|---|---|---|
| Nginx FastCGI cache | Complete FastCGI response | Yes | Nginx configuration and response headers | No separate cache daemon |
| Varnish | Complete HTTP response | Yes | Varnish Configuration Language and HTTP metadata | Yes |
| Application/object cache | Values selected by application code | No | Application, plugin, library, and cache backend | Often |
The table is architectural. It does not say which implementation will be faster for a particular site.
When is Nginx FastCGI cache the simplest fit?
Nginx's official FastCGI module includes cache-path, cache-key, bypass, no-cache, validity, locking, revalidation, and stale-response controls. It can cache responses returned by PHP-FPM and serve a valid cached response without sending that request back to PHP.
That makes it a practical first response cache when:
- Nginx already terminates client traffic and passes PHP to FastCGI;
- most anonymous GET and HEAD responses are shared;
- the team can define logged-in, personalized, preview, checkout, and administrative bypasses;
- the application emits useful cache-control or expiration information; and
- operations already monitor Nginx logs, storage, and configuration.
The difficult part is not creating a cache directory. It is proving the key and bypass policy. Host, scheme, path, query parameters, language, device variation, authentication state, and application cookies may change the correct response. If a relevant dimension is absent from the key or bypass rules, one visitor can receive another state.
Nginx documents that responses carrying Set-Cookie are not cached by default and that response headers such as X-Accel-Expires, Expires, and Cache-Control can affect caching. Treat those defaults as inputs to a design review, not as proof that every personalized response is excluded.
When does Varnish earn the extra layer?
Varnish Cache is a caching HTTP reverse proxy. It belongs between a TLS termination layer and an HTTP backend in a common deployment model. Its documentation illustrates a chain with TLS, Varnish, and backend as separate stages.
Varnish becomes attractive when the team wants its HTTP-oriented policy language, cache inspection, backend selection, grace behavior, or an independent cache tier shared across backends. It may also fit an organization that already operates Varnish consistently across applications.
The cost is another production service and another request boundary. The team must own:
- TLS termination and the connection into Varnish;
- trustworthy forwarding of client, host, and protocol information;
- Varnish policy, reloads, storage, logs, and upgrades;
- health checks and behavior when a backend or cache node fails;
- purge or invalidation authorization; and
- coordination with any Nginx or application cache behind it.
Do not add Varnish merely because it is described as fast. If Nginx FastCGI cache already satisfies the response-cache policy, a second proxy may add more failure modes than value.
When is an application or object cache the right layer?
Choose an application cache when the page cannot safely be shared as one HTTP response but expensive sub-results can be reused. Common cases include authenticated dashboards, personalized pages, APIs assembled from several queries, and templates where only part of the output changes per user.
The application understands the data dependency, so it can use a key tied to the relevant object, locale, permissions, version, or tenant. It can also invalidate that key when the source changes. That precision is its advantage and its responsibility.
Redis is one possible backend, not a synonym for application caching. Redis documents that a cache can evict keys when memory exceeds a configured limit and that eviction policy determines which keys are removed. The application must therefore tolerate misses and rebuild values correctly. If a value cannot be regenerated from an authoritative store, it is not merely a cache entry.
For WordPress, a persistent object cache requires an appropriate drop-in or plugin and backend; setting an old configuration constant alone does not make the current object cache persistent. Other PHP frameworks have their own adapters, namespaces, serialization, and invalidation behavior. Follow the exact application documentation.
Can you combine these caching layers?
Yes, when each layer has a distinct job. A public article page might be served from FastCGI cache, while misses run PHP and reuse cached database objects. A larger platform might put Varnish in front of several application backends and still use application caches for personalized work.
The combination is safe only if invalidation crosses every layer. Updating content in the database may require application-object invalidation and response-cache purge. A response cache must never store logged-in, account, checkout, or permission-dependent output unless the application has deliberately designed a correct private-cache model.
Write a cache map before enabling anything:
- Name the object or response stored at each layer.
- Define the complete cache key and all variation dimensions.
- List requests and responses that must bypass storage and lookup.
- Name the event that invalidates or expires each entry.
- Define behavior on a cold cache, stale data, backend failure, and cache failure.
- Expose a safe diagnostic that shows hit, miss, bypass, and stale states.
- Assign the configuration, purge path, and incident response to an owner.
How does TLS affect the decision?
Nginx can terminate HTTPS and use FastCGI cache inside the same web-server layer. A Varnish design commonly terminates TLS before Varnish, then forwards HTTP plus the protocol and client context the backend requires. That makes proxy trust and header normalization explicit architecture decisions.
Do not accept forwarded client or scheme headers from an untrusted source. Define which proxy is trusted to set them, replace untrusted inbound values at the boundary, and test redirect, secure-cookie, canonical-host, and client-address behavior through the full chain.
An application cache is below HTTP termination. TLS does not change its cached object directly, but scheme, host, tenant, and permissions may still belong in application cache keys.
Which cache should you choose first?
Start with the measured bottleneck:
- If repeated public requests spend time generating the same complete PHP response, evaluate Nginx FastCGI cache first on an existing Nginx/PHP-FPM stack.
- If you need a dedicated HTTP caching tier with Varnish-specific policy or multi-backend operations, evaluate Varnish and budget for the extra proxy boundary.
- If PHP must run but repeats expensive queries or computations, implement the application's supported persistent object or data cache.
- If the bottleneck is an uncached database query, external API, disk operation, or PHP worker shortage, fix or isolate that cause before adding an unrelated cache.
Establish a baseline, change one layer, and compare identical requests at matched load. Record correctness, hit and bypass states, PHP work, database work, errors, memory, disk, and recovery after purge or restart. A high hit ratio is not success if it serves stale or private content.
For sites hosted in Nginx server blocks, document cache policy beside the site's routing ownership; the Nginx server-block guide explains that boundary.