Learn how to reduce load times, improve scalability, and cache smartly using Symfony’s built-in HTTP caching tools, Edge Side Includes (ESI), and the Varnish reverse proxy.
Why HTTP caching matters
HTTP caching sits between your users and your backend, serving popular pages directly from memory without hitting PHP. With proper caching headers, you can reduce server load and deliver content in milliseconds instead of seconds.
1. Setting Cache Headers
Symfony makes it easy to set Cache-Control, Expires, and validation headers using the Response object.
// src/Controller/HomeController.php
use Symfony\Component\HttpFoundation\Response;
public function index(): Response
{
$response = $this->render('home.html.twig');
// Make it public so caches can store it
$response->setPublic();
$response->setMaxAge(3600);
$response->setSharedMaxAge(3600);
// Optional validation
$response->setEtag(md5($response->getContent()));
return $response;
}
The setSharedMaxAge() method controls how long a shared proxy (like Varnish or a CDN) can cache the page, while setMaxAge() affects browsers.
2. Expiration vs. Validation
You can control cache freshness with either expiration (using time-based TTLs) or validation (using ETags or Last-Modified headers). Validation allows caches to check if content changed without downloading it again — saving bandwidth and CPU.
3. Symfony HttpCache (Built-in Proxy)
Symfony ships with a simple built-in reverse proxy called HttpCache. It’s great for development or smaller sites where you can’t use Varnish.
// public/index.php
use App\Kernel;
use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
$kernel = new Kernel('prod', false);
$kernel = new HttpCache($kernel);
$request = Symfony\Component\HttpFoundation\Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
4. Using Varnish for Serious Speed
For high-traffic environments, use Varnish in front of Symfony. It caches pages, handles ESI (Edge Side Includes), and purges stale data faster than PHP ever could.
- Varnish checks its cache for a matching page.
- If found — instant response from memory.
- If not — Varnish asks Symfony for fresh content.
- Symfony sets cache headers; Varnish stores it for next time.
5. Edge Side Includes (ESI)
Sometimes you want part of a page cached for a long time and another part (like user info) refreshed often. ESI lets you mix static and dynamic fragments.
{# templates/article.html.twig #}
{{ article.title }}
<div>{{ article.content|raw }}</div> {{ render_esi(controller('App\\Controller\\SidebarController::recommendations', { 'id': article.id })) }}
The render_esi() function inserts an ESI tag that your reverse proxy (Varnish or HttpCache) can resolve separately, caching each part individually.
6. Cache Invalidation & Purging
Sometimes you need to remove or refresh cached pages. With Varnish, you can send a PURGE request:
# Remove an article from cache
curl -X PURGE https://example.com/article/123
For more advanced invalidation, check out the FOSHttpCache bundle, which adds tag-based purging and integration with Symfony routes.
7. Minimal Varnish Configuration Example
vcl 4.1;
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip != 127.0.0.1) {
return (synth(405, "Not allowed"));
}
return (purge);
}
}
sub vcl_backend_response {
if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
set beresp.do_esi = true;
}
if (!beresp.http.Cache-Control) {
set beresp.ttl = 120s;
}
}
8. Debugging & Validation
- Use
curl -Ito inspectCache-ControlandAgeheaders. - Enable Symfony’s profiler to see cache hits and misses.
- Check your logs for
X-Cache: HITorMISSheaders when testing through Varnish.
9. Step-by-Step Summary
- Identify cacheable pages.
- Set
Cache-Controlheaders. - Enable Symfony’s
HttpCachelocally. - Add Varnish in front for production.
- Implement purging or cache tags for content updates.
10. Advanced Tips
- Use s-maxage for shared caches and max-age for browsers.
- Don’t send
Set-Cookieheaders for cacheable pages. - Use fragment caching or ESI for personalized sections.
- Monitor cache hit ratio to measure real performance gains.
Final Thoughts
Symfony gives you powerful caching tools right out of the box. Whether you’re running a small app or a high-traffic enterprise site, smart use of HTTP caching, ESI, and Varnish can deliver a huge performance boost — often with minimal code changes.