The Complete Magento Varnish VCL Guide 2026
Magento Varnish VCL explained — export the config, understand what the generated VCL does, punch holes with ESI, handle tag-based purging, and verify your cache hit rate.
Magento Varnish VCL is the configuration that turns Varnish into Magento’s recommended full-page cache — serving complete HTML to anonymous visitors without invoking PHP, MySQL or the framework at all. Magento generates the VCL for you, which is both convenient and a trap: teams export it, deploy it, and never understand what it does, so the first cache-invalidation bug becomes unsolvable. This guide covers exporting Magento Varnish VCL, what the generated config actually does, ESI hole-punching, tag-based purging, and verification.
Search intent: informational/procedural — Magento developers configuring or debugging Varnish full-page caching. We cover why Varnish matters, exporting the VCL, its key mechanics, ESI, purging and verification. It pairs with our Redis configuration and cache types guides.
Magento Varnish VCL: Why It Matters More Than Redis
The reason Magento Varnish VCL is the highest-leverage caching work on a Magento store is simple: on a cache hit, the request never reaches PHP. Magento is a heavy application — dependency injection, layout rendering, dozens of database queries — and Varnish lets an anonymous visitor’s category page bypass all of it, returning cached HTML in single-digit milliseconds — the Varnish project introduction explains the model. Redis makes Magento’s own work faster; Magento Varnish VCL means Magento does no work at all for the majority of catalogue traffic. That difference is why Adobe recommends Varnish for production and why it should be configured before micro-optimising anything in the application layer.
Magento Varnish VCL: Exporting and Deploying
You do not write Magento Varnish VCL from scratch — Magento generates it based on your configuration. Set the caching application to Varnish and configure the backend host, then export. The admin path is Stores → Configuration → Advanced → System → Full Page Cache, where you choose “Varnish Caching” and set the backend host and port, TTL and purge hosts; the CLI equivalents are shown below.
# tell Magento to use Varnish as the full-page cache bin/magento config:set system/full_page_cache/caching_application 2 bin/magento config:set system/full_page_cache/ttl 604800 # export the generated VCL (Varnish 6/7 supported) bin/magento varnish:vcl:generate --export-version=6 --backend-host=localhost --backend-port=8080 --output-file=/etc/varnish/default.vcl sudo systemctl reload varnish bin/magento cache:flush
The critical deployment detail is the request path. Varnish must sit in front of your web server — typically Varnish on port 80 with nginx or Apache moved to 8080 as the backend. If Varnish is installed but traffic still reaches nginx directly, nothing is cached and the Magento Varnish VCL is inert. Equally, the backend-host and backend-port in the generated VCL must match where your web server actually listens, or every request returns a 503 guru meditation error.
Magento Varnish VCL: ESI, Purging and What the Config Does
Three mechanisms in the generated Magento Varnish VCL are worth understanding, because they are what you will debug.
ESI hole-punching. A cached page is shared by all anonymous visitors, so anything personal — the mini cart, customer name, recently viewed — cannot be baked into it. Magento marks these blocks as private and Varnish assembles them separately via Edge Side Includes, so the shared page stays cacheable while private fragments are fetched per visitor. When someone reports “my cart shows another customer’s items”, the cause is almost always a block that should be private being cached as shared. Magento’s customer-data/section-load mechanism handles much of this client-side, but ESI remains part of the model.
Tag-based purging. Magento sends cache tags with each response (identifying the products, categories and CMS blocks used to build it). When a product changes, Magento issues a PURGE request to Varnish matching that tag, invalidating only the affected pages rather than the whole cache. This is why the purge_hosts ACL in the Magento Varnish VCL matters: if Magento’s server is not in the ACL, purge requests are rejected and you will serve stale prices after every product update — a subtle and expensive bug.
Grace mode. Varnish can serve slightly stale content while fetching a fresh copy in the background, which protects the origin during traffic spikes and backend slowness. Adobe’s Varnish configuration guide and the Varnish Cache documentation cover both in depth.
| Mechanism | What it does | Symptom when broken |
|---|---|---|
| ESI / private blocks | Serves personal content per visitor | Shared cart or customer data leaks |
| Tag-based purge | Invalidates only affected pages | Stale prices after product edits |
| Purge ACL | Authorises purge requests | Purges silently rejected (403) |
| Grace mode | Serves stale while refreshing | Origin overload during spikes |
| Backend host/port | Points Varnish at the web server | 503 guru meditation on all pages |
Magento Varnish VCL: Verifying Your Hit Rate
A Magento Varnish VCL that is deployed but not actually caching is depressingly common, and it looks identical to a working one until you measure. Two checks settle it. First, enable Magento’s cache debug header in developer mode and inspect responses — X-Magento-Cache-Debug: HIT confirms Varnish served the page from cache. Second, watch Varnish’s own statistics for the cache hit ratio under real traffic.
# does a category page report a cache HIT? curl -sI https://example.com/category.html | grep -i -E "x-magento-cache-debug|age|x-cache" # live hit/miss counters varnishstat -1 | grep -E "cache_hit|cache_miss" # watch purge requests arriving (edit a product to test) varnishlog -q 'ReqMethod eq "PURGE"' # confirm Magento thinks Varnish is the FPC (2 = Varnish) bin/magento config:show system/full_page_cache/caching_application
Interpreting results: a healthy catalogue-heavy store should show a strong hit ratio for anonymous traffic. Consistent MISS on category pages usually means Varnish is not in the request path, or a cookie or query parameter is defeating caching. And remember that logged-in sessions and cart, checkout and account pages are never cached by Magento Varnish VCL — those rely on Redis and application-level tuning instead. Our Magento team deploys and debugs Varnish as part of performance work.
What we have learned deploying Magento Varnish VCL
The purge ACL is the bug we find most often. Everything looks healthy — Varnish caching, good hit rate — but product price changes take a week to appear because Magento’s purge requests are being rejected by the ACL. We test purging explicitly by editing a product and watching varnishlog, rather than assuming invalidation works.
Half the “Varnish is installed” stores we inherit are not caching. Varnish running on a port nothing routes to is indistinguishable from a working setup unless you check headers. Confirming a cache HIT on a real category page is the first thing we do, before any discussion of tuning.
Never hand-edit the generated VCL without a plan to regenerate it. Custom edits get silently lost the next time someone runs the generate command, taking your ACL or custom rules with them. We keep customisations in version control as a documented patch or an include, so regeneration is safe and repeatable.
Frequently Asked Questions About Magento Varnish VCL
What is Magento Varnish VCL?
VCL is Varnish Configuration Language, and Magento Varnish VCL is the configuration Magento generates to make Varnish act as its full-page cache. It defines how requests are cached, how private content is handled via ESI, and how tag-based purge requests invalidate pages. You export it with bin/magento varnish:vcl:generate.
Why use Varnish instead of Magento’s built-in full-page cache?
Because on a cache hit, Varnish returns HTML without invoking PHP at all — Magento does no work. The built-in full-page cache still requires a PHP request. For anonymous catalogue traffic this difference is substantial, which is why Adobe recommends Varnish for production Magento deployments.
How do I generate the Magento Varnish VCL?
Set the caching application to Varnish in Stores → Configuration → Advanced → System → Full Page Cache, then run bin/magento varnish:vcl:generate with your export version, backend host and port, writing to your Varnish config file. Reload Varnish and flush the Magento cache afterwards for the changes to take effect.
Why are stale prices showing after I update products?
Almost always a purge problem. Magento sends tag-based PURGE requests to invalidate affected pages, but if your server is not in the purge_hosts ACL in the Magento Varnish VCL, those requests are rejected and stale pages persist. Test by editing a product and watching varnishlog for incoming PURGE requests.
How do I check whether Varnish is actually caching?
Inspect response headers for X-Magento-Cache-Debug — a HIT confirms Varnish served from cache — and run varnishstat to compare cache_hit against cache_miss under real traffic. Consistent misses usually mean Varnish is not in the request path, or a cookie or query parameter is defeating caching.
Does Varnish cache logged-in customers and checkout?
No. Cart, checkout, account pages and logged-in sessions are never served from the Varnish full-page cache, because they are per-customer. Private content is handled separately via ESI and Magento’s customer-data sections. Speeding up those pages relies on Redis caching and application tuning instead of Magento Varnish VCL.
Varnish Not Caching — or Not Purging?
Our team deploys and debugs Magento Varnish — VCL generation, purge ACLs, ESI and hit-rate verification.