π Volume II: Laravel Performance Tuning Kit
π¨ Topic 26: Blade View Cache
Every Blade template is compiled to PHP. Without caching, this happens on every request.
"Blade templates are beautiful. They compile to PHP.
But compilation takes time β 5-20ms per view.
Without view cache, this happens on EVERY request.
php artisan view:cache compiles all views once.
After caching, views load instantly. 10-30ms saved per request."
β οΈ THE VIEW COMPILATION TRAP
Many developers don't realize that Blade templates need to be compiled to PHP before execution. In development, this happens automatically when you change a view. In production, without caching, Laravel recompiles views on every request β or at least checks if they need recompilation. With 100+ views, this adds significant overhead.
π΄ The Problem: View Compilation Overhead
WHAT HAPPENS WHEN YOU RENDER A BLADE VIEW
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
WITHOUT VIEW CACHE (Every request):
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 1. Check if view exists: resources/views/home.blade.php β
β 2. Check compiled view: storage/framework/views/home.php β
β 3. Compare timestamps (is view newer than compiled?) β
β 4. If newer OR no compiled file: β
β β’ Parse Blade syntax (@if, @foreach, @section, etc.) β
β β’ Convert to PHP β
β β’ Write PHP file to storage/framework/views/ β
β β’ Check if directory is writable β
β 5. Include compiled PHP file β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
For 100 views on a page:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Each @include('header') β trigger the same process β
β 100 views = 100 compilation checks β
β Time: 50-200ms wasted β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
WITH VIEW CACHE (After php artisan view:cache):
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 1. All views pre-compiled during deployment β
β 2. Directly include the compiled PHP files β
β 3. NO timestamp checks β
β 4. NO Blade parsing β
β β
β Time: 1-5ms to include all views β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
THE VIEW SINS
- No view caching in production β Every request recompiles
- Nested partials β Each @include triggers its own checks
- Dynamic view loading β view('dynamic.' . $name) can't be cached
- Conditional includes β @includeIf, @includeWhen still compile
- View composers β Still run, but view compilation is separate
π View Compilation Cost: Before vs After
| Page Type |
Views per Page |
Without Cache |
With Cache |
Savings |
| Simple page (1 view)
| 1
| 5-15ms
| 1-2ms
| 70-80% reduction
|
| Blog post (layout + content + sidebar)
| 5-10
| 15-40ms
| 2-5ms
| 70-80% reduction
|
| E-commerce product page (header, footer, product, reviews, related)
| 15-25
| 30-80ms
| 4-10ms
| 70-80% reduction
|
| Complex dashboard (many widgets)
| 30-50
| 60-150ms
| 10-20ms
| 70-80% reduction
|
THE BOTTOM LINE
View caching saves 10-50ms per request on typical Laravel pages. For high-traffic sites with 1M requests/day, that's 10-50 seconds of CPU time saved daily.
β
The Solution: php artisan view:cache
THE GOLDEN RULE OF BLADE
Always run php artisan view:cache in production after every deployment.
π BAD (No cache)
# Deploy script WITHOUT view cache
git pull
composer install --no-dev
php artisan migrate
php artisan config:cache
php artisan route:cache
# Views are NOT cached
# First request after deploy: compiles ALL views
# Every request: checks timestamps on ALL views
π GOOD (With cache)
# Deploy script WITH view cache
git pull
composer install --no-dev
php artisan migrate
php artisan config:cache
php artisan route:cache
php artisan view:cache # β CRITICAL!
# All views pre-compiled during deployment
# No timestamp checks in production
# Views load instantly
THE OPTIMIZE COMMAND (Includes view:cache)
# One command to rule them all
php artisan optimize
# This runs:
# - config:cache
# - route:cache
# - view:cache
# - event:cache
# ALWAYS run optimize after deployment!
π What view:cache Actually Does
BEFORE view:cache
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
resources/views/
βββ home.blade.php
βββ layout.blade.php
βββ partials/
β βββ header.blade.php
β βββ footer.blade.php
βββ ...
storage/framework/views/
βββ (empty or few files)
On every request:
β’ Blade engine checks each .blade.php modification time
β’ Compiles if newer than cached version
β’ Writes to storage/framework/views/
AFTER view:cache
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
resources/views/
βββ home.blade.php
βββ layout.blade.php
βββ ...
storage/framework/views/
βββ 1a2b3c4d5e6f7g8h9i0j.php (compiled home.blade.php)
βββ 2b3c4d5e6f7g8h9i0j1k.php (compiled layout.blade.php)
βββ 3c4d5e6f7g8h9i0j1k2l.php (compiled header.blade.php)
βββ ...
In production:
β’ No timestamp checks (Laravel assumes cache is fresh)
β’ Directly includes pre-compiled PHP files
β’ 70-80% reduction in view rendering time
β οΈ View Cache Limitations
WHAT VIEW CACHE DOES NOT CACHE
- Dynamic view names β
view('dynamic.' . $variable)
- Views that don't exist yet β Must exist at cache time
- The PHP execution β Cache only compiles BladeβPHP, not the output
- View composers β Still run on every request
- @inject services β Still resolved per request
WHEN VIEW CACHE BREAKS
If you add a new view after running view:cache, it won't be compiled until you run it again. Views must exist at cache time.
# Always re-run view:cache after adding new views
php artisan view:cache
# Or clear and re-cache
php artisan view:clear
php artisan view:cache
π Dynamic Views and Cache (The Exception)
FOR DYNAMIC VIEW NAMES
// BAD: Cannot be cached efficiently
view('pages.' . $pageSlug)->render();
// GOOD: Use a mapping or cache the result
$allowedPages = ['home', 'about', 'contact'];
if (in_array($pageSlug, $allowedPages)) {
view('pages.' . $pageSlug)->render();
}
// BEST: Cache the compiled view output, not the name
$html = Cache::remember("page.{$pageSlug}", 3600, function () use ($pageSlug) {
return view('pages.' . $pageSlug)->render();
});
π View Composers (Still Run, That's Fine)
VIEW COMPOSERS ARE NOT CACHED
View composers are still executed on every request β this is intentional and good. They prepare the data for the view. Only the BladeβPHP compilation is cached, not the data binding.
// View composer runs on EVERY request (by design)
View::composer('profile', function ($view) {
$view->with('user', auth()->user()); // Runs per request β
});
// But the view itself is cached
// So: Compilation = once, Data binding = per request
// This is exactly what you want!
π§ Troubleshooting View Cache
COMMON ISSUES
- New views not showing β Re-run
view:cache
- Changes not reflecting β Run
view:clear then view:cache
- Storage directory not writable β Check permissions on storage/framework/views
- Different servers (load balanced) β Each server needs its own cache, or share storage
CLEARING VIEW CACHE
# Clear all compiled views
php artisan view:clear
# Check if cache is enabled
php artisan optimize:status
# Verify views are cached
ls -la storage/framework/views/
# Should see many .php files
π Topic 26 Summary: Blade View Cache
| Situation |
Without View Cache |
With View Cache |
Improvement |
| First request after deploy
| Compiles all views (100-300ms)
| Already compiled (5-10ms)
| 90-95% faster
|
| Subsequent requests
| Checks timestamps (10-50ms)
| Direct include (1-5ms)
| 70-90% faster
|
| Page with 20 partials
| 20 timestamp checks (20-60ms)
| 0 checks (2-5ms)
| 80-90% faster
|
π THE RULE: Always run php artisan view:cache (or php artisan optimize) after every deployment in production. It's free performance β 10-50ms saved per request. Without it, you're wasting CPU checking file timestamps on every request.
NEXT TOPIC PREVIEW
Topic 27: CAP Theorem β Consistency vs Availability vs Partition Tolerance. Why you can't have all three in distributed systems. How to choose the right trade-off for your app.