spatie/laravel-varnish
Integrate Varnish 4/5 with Laravel: add middleware to force-cache selected routes and flush/purge the Varnish cache from within your app. Includes simple configuration and supports Laravel and Lumen.
Installation:
composer require spatie/laravel-varnish
Publish the config file:
php artisan vendor:publish --provider="Spatie\Varnish\VarnishServiceProvider"
Configure Varnish:
Edit config/varnish.php with your Varnish server details (host, port, secret for purge requests).
First Use Case:
Apply the VarnishCache middleware to a route to ensure its responses are cached by Varnish:
Route::get('/cached-route', [Controller::class, 'cachedMethod'])
->middleware('varnish');
Flushing Cache:
Use the varnish:flush Artisan command to clear Varnish cache:
php artisan varnish:flush
Or programmatically:
use Spatie\Varnish\Facades\Varnish;
Varnish::flush();
Route-Level Caching:
Apply varnish middleware to routes where you want Varnish to cache responses aggressively:
Route::get('/products', [ProductController::class, 'index'])
->middleware(['web', 'varnish']);
Conditional Caching: Combine with Laravel's built-in caching middleware for granular control:
Route::get('/dynamic-content', [DynamicController::class, 'show'])
->middleware(['web', 'cache.headers:public,max_age=3600', 'varnish']);
Development vs. Production:
Disable Varnish in config/varnish.php during development:
'enabled' => env('APP_ENV') !== 'local',
Purge Strategies:
Varnish::flush() after critical data changes (e.g., admin actions).use Spatie\Varnish\Facades\Varnish;
ProductUpdated::dispatch($product)
->then(function () {
Varnish::flush();
});
Edge Caching:
Pair with spatie/laravel-cache-control to set Cache-Control headers dynamically:
return response()->json($data)
->header('Cache-Control', 'public, max_age=300')
->middleware('varnish');
Queue Purges: Offload purges to a queue to avoid blocking requests:
use Spatie\Varnish\Facades\Varnish;
use Illuminate\Support\Facades\Queue;
Queue::push(function () {
Varnish::flush();
});
VCL Snippets:
Customize Varnish behavior by extending the default VCL template (located at resources/views/vendor/varnish/vcl.blade.php).
Purge Delays:
Varnish::flush() sparingly in production to avoid performance spikes.Secret Mismatch:
secret in config/varnish.php matches the Varnish configuration (secret in default.vcl).varnishlog -g request -q "ReqHeader") for rejected requests.Middleware Order:
varnish middleware after web but before route-specific middleware to avoid caching uncached responses.Route::middleware(['web', 'varnish', 'auth'])->get('/admin', ...);
Dynamic Content Leaks:
? or POST requests, as Varnish treats them as unique URLs.Varnish::ignore() to exclude routes:
Varnish::ignore('/search*');
Check Cache Status:
Use varnishstat or varnishadm to monitor cache hits/misses:
varnishstat -1 | grep -E "main\.client_req|main\.cache_hit"
Log Purges:
Enable debug logging in config/varnish.php:
'log_purges' => true,
Check Laravel logs for purge confirmation.
TTL Overrides: The package defaults to caching responses for 1 hour. Override via headers:
return response()->view('page')
->header('X-Varnish-TTL', 3600); // 1 hour
Environment Variables:
Bind Varnish settings to .env for easier deployment:
VARNISH_HOST=varnish.example.com
VARNISH_PORT=6081
VARNISH_SECRET=your_secret_here
HTTPS Handling:
Ensure Varnish is configured to handle HTTPS (e.g., via backend directives in VCL) if your Laravel app uses SSL.
Custom Purge Logic:
Extend the Spatie\Varnish\VarnishManager class to add custom purge logic:
namespace App\Services;
use Spatie\Varnish\VarnishManager;
class CustomVarnishManager extends VarnishManager
{
public function purgeByTag($tag)
{
$this->purge("tag.$tag");
}
}
VCL Customization: Override the default VCL template by publishing and modifying:
php artisan vendor:publish --tag=varnish-vcl
Then update resources/views/vendor/varnish/vcl.blade.php.
Event-Based Purges: Listen to Laravel events and trigger purges:
use Illuminate\Cache\Events\CacheMissed;
use Spatie\Varnish\Facades\Varnish;
CacheMissed::listen(function ($key) {
if (str_starts_with($key, 'products_')) {
Varnish::flush();
}
});
Multi-Varnish Instances:
Support multiple Varnish servers by extending the VarnishManager:
Varnish::addServer('cdn1', 'cdn1.example.com', 6081, 'secret1');
Varnish::addServer('cdn2', 'cdn2.example.com', 6081, 'secret2');
Varnish::flush(['cdn1', 'cdn2']); // Flush all servers
How can I help you explore Laravel packages today?