Varnish Cache for PrestaShop: When Full Page Cache Modules Aren't Enough
What Varnish Is and Why It Matters for PrestaShop
Varnish Cache is an HTTP reverse proxy that sits between your web server and the internet, serving cached copies of pages without ever touching PHP or MySQL. When a visitor requests a page that Varnish has cached, the response comes directly from memory in microseconds. PHP never executes. MySQL never receives a query. The web server barely notices the request happened.
This is fundamentally different from how PHP-based full page cache (FPC) modules work in PrestaShop. An FPC module still runs within PHP. The request hits Apache or Nginx, PHP boots, PrestaShop initializes (loading configuration, establishing database connections, parsing routes), and then the FPC module intercepts the request before the full controller logic runs, serving a cached HTML file. While this is significantly faster than rendering the page from scratch, it still involves starting PHP and loading the PrestaShop framework. That overhead, typically 50-200 milliseconds even for a cache hit, adds up under load.
Varnish eliminates that overhead entirely. A Varnish cache hit is served in 1-5 milliseconds. Under heavy traffic, the difference is dramatic. A PrestaShop store that struggles to handle 100 concurrent users with an FPC module can serve thousands of concurrent users with Varnish, because the vast majority of requests never reach the PHP backend at all.
When PHP Full Page Cache Modules Are Sufficient
Before investing in Varnish, it is worth understanding when a PHP-based FPC module is good enough. For many PrestaShop stores, it is.
If your store receives fewer than 50,000 daily page views, a well-configured FPC module will handle the load without problems. The additional complexity of Varnish is not justified when your server has spare capacity. If your server response times with FPC are consistently under 200 milliseconds, your visitors are already getting fast page loads. The bottleneck at that point is likely frontend rendering (CSS, JavaScript, images) rather than server response time.
FPC modules also handle some PrestaShop-specific scenarios more gracefully than Varnish because they run inside the application. They can check whether a user is logged in, whether the cart has items, and whether certain dynamic content needs to be personalized, all within the same PHP process. With Varnish, these checks must be handled through cookie inspection and cache variation rules, which adds configuration complexity.
Consider Varnish when your store regularly handles traffic spikes (flash sales, marketing campaigns, seasonal peaks) that overwhelm your PHP capacity, when you need sub-10ms response times for SEO or user experience reasons, when your hosting budget is limited and you need to serve more traffic from the same hardware, or when your store serves a high ratio of anonymous browsing traffic (category pages, product pages) relative to cart and checkout activity.
How Varnish Works: The Request Flow
Understanding the request flow through Varnish is essential for configuring it correctly with PrestaShop.
Request Arrives
When a visitor requests a page, the request hits Varnish first (Varnish listens on port 80 or 443 if terminated by a frontend proxy). Varnish examines the request: the URL, the HTTP method, the cookies, and the headers.
Cache Lookup
Varnish checks its cache for a stored response matching this request. The cache key is typically based on the URL and selected headers. If a matching response exists and has not expired, Varnish serves it directly. This is a cache hit. The response is sent to the visitor and the backend server is never contacted.
Cache Miss
If no matching cached response exists, Varnish forwards the request to the backend server (Apache or Nginx running PrestaShop). PrestaShop processes the request normally, generates the HTML response, and sends it back to Varnish. Varnish stores the response in its cache (if the response is cacheable) and forwards it to the visitor. Subsequent requests for the same page will be served from cache.
Cache Invalidation
When product data changes, prices update, or content is modified, the cached version becomes stale. Varnish needs to be told to discard the old cached version so it fetches a fresh one from the backend. This is cache invalidation, and it is the hardest part of any caching system to get right.
VCL Configuration for PrestaShop
Varnish Configuration Language (VCL) is a domain-specific language that controls how Varnish handles requests. A proper VCL configuration for PrestaShop must handle several PrestaShop-specific behaviors.
Backend Definition
The backend definition tells Varnish where to forward cache misses. For a typical PrestaShop setup where Apache or Nginx runs on the same server on port 8080:
backend default {
.host = "127.0.0.1";
.port = "8080";
.connect_timeout = 5s;
.first_byte_timeout = 60s;
.between_bytes_timeout = 10s;
}
The timeouts are important. PrestaShop pages can take several seconds to generate on a cold cache, especially category pages with many products. Setting first_byte_timeout too low causes Varnish to return a 503 error before PrestaShop finishes generating the page.
Handling Cookies and Sessions
Cookies are the biggest challenge when caching PrestaShop with Varnish. PrestaShop sets several cookies by default, and Varnish treats any request with cookies as uncacheable unless instructed otherwise. If you do not handle cookies in your VCL, Varnish will cache almost nothing.
PrestaShop sets these cookies on most requests: the session cookie (typically named PrestaShop-xxxx), the cart-related cookies, Google Analytics cookies (_ga, _gid, _gat), and various tracking cookies from marketing tools. Of these, only the PrestaShop session cookie matters for cache behavior. Analytics and tracking cookies should be stripped from the request before the cache lookup so they do not prevent caching.
In your VCL vcl_recv subroutine, strip non-essential cookies:
sub vcl_recv {
# Remove Google Analytics and other tracking cookies
set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_ga|_gid|_gat|__utm[a-z]+|_fbp|_gcl_[a-z]+)=[^;]*", "");
# Remove empty cookie header
if (req.http.Cookie ~ "^\s*$") {
unset req.http.Cookie;
}
}
Deciding What to Cache
Not every PrestaShop page should be cached. The VCL must distinguish between cacheable and non-cacheable requests.
Always cache: Product pages for anonymous visitors, category listing pages, CMS pages (about, terms, contact), the homepage, manufacturer and supplier pages, sitemap pages.
Never cache: The shopping cart page, checkout pages (all steps), the customer account area (orders, addresses, personal info), the login and registration pages, any page for a logged-in customer, POST requests, AJAX requests that modify state (add to cart, update quantity).
The VCL logic for this typically checks the URL path and the presence of session cookies:
sub vcl_recv {
# Do not cache POST requests
if (req.method == "POST") {
return (pass);
}
# Do not cache admin area
if (req.url ~ "^/admin") {
return (pass);
}
# Do not cache checkout and cart
if (req.url ~ "(cart|order|login|my-account|module/)" ) {
return (pass);
}
# Do not cache if customer has items in cart
if (req.http.Cookie ~ "PrestaShop-") {
return (pass);
}
return (hash);
}
Setting Cache Duration
In the vcl_backend_response subroutine, you control how long Varnish caches each response. PrestaShop sends Cache-Control headers that typically say no-cache or private because it assumes every response might contain personalized content. You need to override these for pages you know are safe to cache:
sub vcl_backend_response {
# Cache product and category pages for 1 hour
if (bereq.url ~ "^/([0-9]+-|[a-z]+-[0-9]+)") {
set beresp.ttl = 1h;
unset beresp.http.Set-Cookie;
}
# Cache static assets for 1 day
if (bereq.url ~ "\.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2|ttf)$") {
set beresp.ttl = 1d;
unset beresp.http.Set-Cookie;
}
}
Stripping Set-Cookie from cached responses is critical. If a cached response includes a Set-Cookie header, Varnish will not cache it by default, and even if forced to cache it, it would set the same session cookie for every visitor, causing session hijacking.
Cache Invalidation with PURGE Requests
When a product price changes, a new product is added, or content is updated, the cached version must be invalidated. Varnish supports PURGE requests: a special HTTP method that tells Varnish to remove a specific URL from its cache.
Configuring PURGE Support
Add PURGE handling to your VCL:
acl purge {
"127.0.0.1";
"localhost";
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return (synth(405, "Not allowed."));
}
return (purge);
}
}
The ACL restricts PURGE requests to localhost, preventing external users from flushing your cache.
Triggering Purges from PrestaShop
PrestaShop does not send PURGE requests natively. You need a module or custom hook that detects when cacheable content changes and sends a PURGE request to Varnish. The module hooks into PrestaShop events like actionProductUpdate, actionCategoryUpdate, and actionCMSPageUpdate. When these events fire, the module sends an HTTP PURGE request to the corresponding URL on the Varnish server.
For a product update, the module would purge the product URL, the category URLs the product belongs to (because category listing pages show product prices and availability), and potentially the homepage if it displays featured products. This cascade of purges is necessary to prevent stale data from appearing anywhere on the site.
Ban-Based Invalidation
For scenarios where many URLs need to be purged at once (a site-wide price update, a design change, a new promotion banner), individual PURGE requests are impractical. Varnish supports bans, which are pattern-based invalidation rules. A ban tells Varnish to discard any cached object matching a pattern:
sub vcl_recv {
if (req.method == "BAN") {
if (!client.ip ~ purge) {
return (synth(405, "Not allowed."));
}
ban("req.url ~ " + req.http.X-Ban-Pattern);
return (synth(200, "Banned."));
}
}
Sending a BAN request with the header X-Ban-Pattern: /category/ would invalidate all cached category pages in one operation.
Edge Side Includes (ESI) for Dynamic Blocks
Many PrestaShop pages contain a mix of static and dynamic content. The product listing on a category page is the same for every visitor, but the header showing the cart count is personalized. Without ESI, you cannot cache the page at all because the dynamic header makes the whole response visitor-specific.
Edge Side Includes solve this by allowing you to mark sections of the page as separately fetched fragments. Varnish assembles the final page from cached and uncached fragments.
How ESI Works
In your Smarty template, instead of rendering the cart widget directly, you include an ESI tag:
<esi:include src="/module/cartwidget/ajax" />
When Varnish processes the cached page, it encounters the ESI tag and makes a separate backend request for that fragment. The main page body is served from cache, while the cart widget is fetched fresh from PrestaShop. The assembled response includes both the cached body and the fresh cart widget.
Enable ESI processing in your VCL:
sub vcl_backend_response {
set beresp.do_esi = true;
}
ESI Considerations for PrestaShop
Implementing ESI requires modifying your PrestaShop templates to separate dynamic content into ESI-compatible fragments. Each fragment needs its own URL endpoint that returns just the HTML for that block. The fragments that are typically dynamic and need ESI treatment include the cart summary widget (item count, total), the customer greeting ("Hello, John"), any personalized product recommendations, the login/logout link, and recently viewed products.
The effort required to implement ESI properly is significant. Each dynamic fragment needs a dedicated controller, the templates need restructuring, and the caching rules for each fragment need individual tuning. This is one of the reasons Varnish is considered an advanced optimization, it works best when the application is designed with it in mind.
Backend Health Checks
Varnish can monitor the health of your backend server and take action when it becomes unavailable. This is configured in the backend definition:
backend default {
.host = "127.0.0.1";
.port = "8080";
.probe = {
.url = "/ping.php";
.timeout = 2s;
.interval = 5s;
.window = 5;
.threshold = 3;
}
}
Varnish sends a request to /ping.php every 5 seconds. If 3 out of the last 5 checks fail, Varnish marks the backend as sick. While the backend is sick, Varnish can serve stale cached content (grace mode) instead of returning errors to visitors. This means your store remains partially available even when the PHP backend crashes or restarts.
The grace mode configuration determines how long Varnish will serve stale content:
sub vcl_backend_response {
set beresp.grace = 6h;
}
With a 6-hour grace, if your backend goes down, visitors will see cached pages (even if they are up to 6 hours old) rather than error pages. Product prices might be slightly outdated, but the store remains functional while you fix the backend issue.
Performance Benchmarks
The performance difference between no cache, PHP FPC, and Varnish is substantial and measurable.
No cache (bare PrestaShop): A typical PrestaShop product page takes 200-800 milliseconds to generate, depending on server hardware, number of modules loaded, and database query count. Under load, response times increase because PHP workers are saturated. A single server might handle 20-50 concurrent users before response times become unacceptable.
PHP FPC module: Cache hits serve in 30-100 milliseconds because PHP still boots and the framework partially initializes. Under load, performance is much better because cached responses require minimal PHP processing time. A single server can handle 200-500 concurrent users depending on configuration. Cache misses still take the full rendering time.
Varnish: Cache hits serve in 1-5 milliseconds. Under load, Varnish itself can handle thousands of concurrent connections because it is written in C and designed specifically for this workload. The backend server only handles cache misses, which are a small fraction of total traffic on a properly configured system. The same hardware that struggles with 50 concurrent users without caching can handle 5,000 or more with Varnish.
These numbers illustrate why Varnish is worth the configuration complexity for high-traffic stores. The performance improvement is not incremental, it is an order of magnitude.
Hosting Requirements
Varnish has specific hosting requirements that not every PrestaShop hosting environment can accommodate.
Server Access
You need root access to install and configure Varnish. Shared hosting plans do not support Varnish because it requires its own process listening on a port and intercepting all HTTP traffic. You need a VPS, dedicated server, or cloud instance where you control the full server stack.
Memory
Varnish stores its cache in RAM. The amount of RAM you need depends on the number of unique pages in your catalog and the size of each cached response. A rough formula: number of cacheable pages multiplied by average page size gives you the minimum cache size. A store with 5,000 products, 200 categories, and an average page size of 50KB needs approximately 260MB of cache RAM. Add overhead for Varnish itself and you should allocate at least 512MB. For larger catalogs, 1-2GB is common.
Port Configuration
In a standard setup, Varnish listens on port 80 (the default HTTP port) and forwards cache misses to the web server on a different port (commonly 8080). This means you need to reconfigure Apache or Nginx to listen on port 8080 instead of 80. If you are using HTTPS (and you should be), you typically put Nginx in front of Varnish to handle SSL termination: Nginx on port 443 terminates SSL and forwards to Varnish on port 80, which forwards cache misses to Apache or PHP-FPM on port 8080.
Docker Setup Example
Running Varnish in Docker alongside a PrestaShop container is a clean way to add Varnish to an existing setup without modifying the host system.
Docker Compose Configuration
A basic Docker Compose setup with Varnish, Nginx for SSL, and PrestaShop:
services:
varnish:
image: varnish:7.4
ports:
- "80:80"
volumes:
- ./varnish/default.vcl:/etc/varnish/default.vcl:ro
environment:
- VARNISH_SIZE=512m
depends_on:
- prestashop
prestashop:
image: prestashop/prestashop:8
expose:
- "80"
environment:
- DB_SERVER=db
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=secretpassword
- MYSQL_DATABASE=prestashop
In this setup, Varnish is the entry point on port 80. The PrestaShop container does not expose its port to the host, only to the Docker network. The VCL backend host would be prestashop (the Docker service name) on port 80.
VCL for Docker
The VCL backend definition for Docker uses the service name instead of localhost:
backend default {
.host = "prestashop";
.port = "80";
}
Docker's internal DNS resolves the service name to the container IP. The rest of the VCL configuration remains the same as a non-Docker setup.
Cache Storage in Docker
By default, the Varnish Docker image uses in-memory storage (malloc), which is ideal for performance. The VARNISH_SIZE environment variable controls how much memory Varnish allocates for its cache. Set this to a value that fits within your container's memory limits while leaving room for the Varnish process itself.
For persistent cache that survives container restarts, you can use file-based storage by mounting a volume, but this is rarely necessary. The cache warms up quickly (within minutes of receiving traffic) and file-based storage is slower than memory-based storage.
Monitoring Varnish Performance
Varnish provides built-in tools for monitoring cache performance.
The varnishstat command shows real-time statistics including cache hit rate, backend connections, and memory usage. The most important metric is the hit rate, which should be 85% or higher for a well-configured setup. If your hit rate is below 70%, review your VCL rules because too many requests are passing through to the backend.
The varnishlog command shows detailed per-request logs, which are invaluable for debugging why specific requests are not being cached. You can filter by URL pattern, response code, or cache hit/miss status.
The varnishtop command shows a ranked list of the most frequent log entries, helping you identify patterns in cache misses or errors.
Common Pitfalls
Forgetting to Strip Cookies
The single most common Varnish misconfiguration with PrestaShop is not stripping analytics and tracking cookies. These cookies are present on virtually every request and make every request unique from Varnish's perspective, resulting in a 0% hit rate. Always strip cookies you do not need for cache variation.
Caching Personalized Content
If your VCL is too aggressive, it will cache pages that contain personalized content (logged-in user greeting, cart contents) and serve them to other visitors. This causes serious usability issues and potential privacy problems. Always pass requests that contain session cookies to the backend.
Not Invalidating on Content Changes
Without a proper purging mechanism, content changes in the back office will not be visible until cached pages expire naturally. For a store with active inventory changes, this means visitors might see out-of-stock products, wrong prices, or outdated descriptions. Implement PURGE or BAN support and integrate it with PrestaShop's update hooks.
Ignoring HTTPS
Varnish does not handle SSL natively. You must put an SSL-terminating proxy (Nginx, HAProxy, or a cloud load balancer) in front of Varnish. Failing to plan for this in your architecture leads to mixed content issues, redirect loops, or an inability to serve HTTPS traffic at all.
Is Varnish Right for Your Store
Varnish is a powerful tool, but it is not the right choice for every PrestaShop store. It adds operational complexity: another service to monitor, another configuration language to learn, another layer in your debugging process. The benefits are clear and measurable for stores that need them, but they come at a cost in setup time, maintenance, and troubleshooting difficulty.
If your store serves fewer than 50,000 page views per day and your server handles the load comfortably with an FPC module, Varnish is unnecessary complexity. If your store regularly faces traffic spikes that overwhelm your server, serves a high volume of anonymous browsing traffic, or needs the fastest possible response times for SEO or user experience, Varnish provides a level of performance that no PHP-based caching solution can match.
Start with proper PrestaShop optimization (query optimization, module audit, PHP OPcache, image optimization) and an FPC module. If those optimizations are not enough, Varnish is the next step in the performance scaling ladder.
For more details, read our guides: PrestaShop Cache: Full Page Cache Modules Explained and Redis Cache for PrestaShop: Setup and Performance Gains.
Was this answer helpful?
Still have questions?
Can't find what you're looking for? Send us your question and we'll get back to you quickly.