
September 09, 2026
14 min read
By Kokil Thapa | Last reviewed: September 2026
Laravel caching strategies: config, route, view, and data are the four layers that separate a fast production app from one that re-parses PHP files on every request. Laravel 13 runs on PHP 8.3 or higher; Laravel 12 still works on PHP 8.2 and remains supported through February 2027. Most teams I work with already use Redis for Laravel application caching, yet they skip route and config caching entirely. That gap shows up as slow cold starts after deploy and unnecessary CPU use under traffic spikes.
config:cache and route:cache in production, compiling Blade with view:cache, and storing query results in Redis or Memcached via Cache::remember()—each layer targets a different boot cost.What Are Laravel Caching Strategies for Config, Route, View, and Data?
Think of Laravel boot as four separate cost centres. Config caching removes repeated parsing of every file in config/. Route caching pre-compiles your route table so the router skips regex matching work. View caching compiles Blade templates to plain PHP ahead of time. Data caching stores expensive query or API results outside the request cycle.
These layers stack. They do not replace each other. A site with perfect Redis data caching still benefits from config and route caches because those run before your controller ever executes. On a legal-tech portal I maintain, skipping route cache added roughly 80–120 ms to every request on a modest VPS. After enabling it, TTFB dropped enough that Core Web Vitals stopped flagging server response time.
Your .env file is read once when config is cached. That is why you must never call env() outside config files in production. Laravel documents this explicitly, and breaking it is one of the most common post-deploy bugs I see on client projects.
Config cache mechanics
Running php artisan config:cache merges all config files into a single bootstrap file at bootstrap/cache/config.php. Reads become a single include instead of dozens of file operations. The trade-off is that config changes require re-running the command or clearing the cache.
Route cache mechanics
php artisan route:cache serialises the route collection. Closures cannot be cached—only controller and invokable routes work. If your routes file uses inline closures for quick tests, move them to controllers before caching.
How Do You Cache Laravel Config and Routes in Production?
Production deploy scripts should treat cache warming as a required step, not an optional optimisation. I use Deployer 7 on several sister sites sharing GitLab CI, and the deploy recipe always runs cache commands after the symlink swap and PHP-FPM reload. The order matters because stale opcache can serve old bootstrap files if you cache before swapping releases.
A typical Deployer task block looks like this:
task('artisan:optimize', function () {
run('{{bin/php}} {{release_path}}/artisan config:cache');
run('{{bin/php}} {{release_path}}/artisan route:cache');
run('{{bin/php}} {{release_path}}/artisan view:cache');
run('{{bin/php}} {{release_path}}/artisan event:cache');
})->once(); Run these only in production. During local development, cached config hides .env changes until you run php artisan config:clear. I have lost hours to that mistake. Keep a shell alias if it helps.
For teams using testing and optimisation services, the first audit item is usually whether production actually runs these commands. Many hosting panels deploy code but skip Artisan entirely.
Environment-specific config
Set APP_ENV=production and APP_DEBUG=false before caching config. Debug mode disables some optimisations and exposes stack traces. Your config/cache.php default store should point to Redis in production:
CACHE_STORE=redis
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379 Redis 8.10 is the current anchor version. On budget VPS hosts in Nepal, a single Redis instance on the same server costs nothing extra beyond RAM. Expect roughly Rs 0 if Redis is already bundled, versus Rs 1,500–3,000/month (~USD 11–22) for a managed Redis add-on from cloud providers.
When Should You Use View Caching vs Response Caching in Laravel?
View caching compiles Blade to PHP files under storage/framework/views. Response caching stores the entire HTTP output—headers and body—for a given URL. They solve different problems.
Use php artisan view:cache on every production deploy. It removes per-request Blade compilation cost. That matters on pages with deep partial includes, like eCommerce category trees or legal service directories with shared sidebars.
Response caching—via packages like spatie/laravel-responsecache or middleware you write yourself—fits mostly static pages: blog posts, landing pages, documentation. It does not fit authenticated dashboards, carts, or anything with CSRF tokens in the HTML.
| Layer | Command / API | Best for | Invalidation | Gotcha |
|---|---|---|---|---|
| Config cache | config:cache | All production apps | Re-run on deploy | env() outside config breaks |
| Route cache | route:cache | Apps with 50+ routes | Re-run on deploy | Closures cannot cache |
| View cache | view:cache | Blade-heavy UIs | Re-run on deploy | Does not cache data |
| Data cache | Cache::remember() | Expensive queries, API calls | TTL or event-driven | Stale reads if TTL too long |
| Response cache | Middleware / package | Anonymous HTML pages | Tag flush or TTL | CSRF and session bleed |
On a WooCommerce florist site in the portfolio, view caching helped, but product stock still needed data-layer invalidation. Caching the HTML would have shown wrong availability. Match the cache type to what actually changes.
Read improving web performance with caching strategies for browser and CDN layers that complement Laravel-side work. Server caching alone does not fix unoptimised assets or missing compression.
How Do You Cache Application Data Safely in Laravel?
Data caching is where most performance wins live after boot optimisations are in place. The pattern is simple: wrap expensive work in Cache::remember(), set a TTL, and invalidate when underlying data changes.
Basic remember pattern
use Illuminate\Support\Facades\Cache;
$categories = Cache::remember('shop.categories', 3600, function () {
return Category::with('children')
->whereNull('parent_id')
->orderBy('sort_order')
->get();
}); Use descriptive, namespaced keys. Prefix by tenant or locale when you serve multiple sites from one codebase: tenant:42:shop.categories. Collisions across environments are another common bug—include APP_NAME or environment in the key when Redis is shared.
Cache tags and invalidation
Redis supports cache tags in Laravel when your store driver allows it. Tag related keys and flush the group on update:
Cache::tags(['products'])->put("product.{$id}", $product, 3600);
/* On product update */
Cache::tags(['products'])->flush(); File and database cache drivers do not support tags efficiently. If you are still on the file driver, migrate to Redis before building tag-based invalidation. See database query caching strategies for overlap between ORM-level and application-level caching.
Eloquent and query caching
Laravel does not cache Eloquent results automatically. You must opt in. For read-heavy reporting, consider rememberForever() with explicit invalidation on writes rather than a short TTL that hammers the database on expiry.
Watch for N+1 queries inside cached closures. Caching a collection that lazy-loads relations on access still triggers extra queries when the view iterates. Eager load inside the closure. The Laravel N+1 detection guide covers tooling like Debugbar and Telescope for catching this during development.
On booking systems like Adventure Third Pole Trek, I cache itinerary lists and destination filters but never cache user-specific booking state. Personalised data belongs in the session or a short-lived cache keyed by user ID with tight TTL.
Which Cache Driver Should You Choose for Laravel in 2026?
Your config/cache.php default store drives every Cache facade call. Pick based on infrastructure, not blog benchmarks.
- Redis: Default choice for production. Supports tags, pub/sub, queues, and sessions on one service. Use separate Redis databases (
REDIS_CACHE_DB=1) to isolate cache from queues. - Memcached 1.6.x: Fast pure cache when you already run it and do not need persistence or Laravel queue integration.
- Database: Works on shared hosting with only MySQL available. Creates a
cachetable via migration. Slower than Redis but better than no cache. - File: Fine for local dev and single-server hobby projects. Poor choice for horizontal scaling—each app server holds its own copy.
For PostgreSQL-backed apps, read PostgreSQL for Laravel developers alongside caching—index tuning and cache layers solve different bottlenecks. MySQL 9.7 and MariaDB 12.3 remain common on Nepali shared hosts; Redis still sits beside them as the cache tier.
Official reference: the Laravel 12.x cache documentation covers drivers, tags, and atomic locks. Laravel 13 docs follow the same API with minor config additions.
How Do You Invalidate Laravel Caches After Deployment?
Stale cache is worse than no cache. Users see old prices, outdated legal fees, or wrong appointment slots. Build invalidation into your deploy and your domain events.
- Boot caches: Re-run
config:cache,route:cache, andview:cacheon every deploy. Never rely on the previous release's bootstrap files. - Data caches: Flush selectively with tags, or bump a version prefix in keys (
v3:products.list) when schema changes make old serialised objects invalid. - Opcache: Reload PHP-FPM after symlink swap. Without reload, workers may serve old compiled PHP including cached config files.
- CDN / edge: Purge edge cache when response caching sits behind Cloudflare or similar. Application cache and CDN cache are independent layers.
- Queues: Restart queue workers after deploy so they load new code.
php artisan queue:restartsignals graceful restart.
On rollback, clear boot caches before restoring the previous release:
php artisan config:clear
php artisan route:clear
php artisan view:clear
php artisan cache:clear Use cache:clear carefully in production—it wipes all data cache keys. Prefer tag flushes or targeted Cache::forget() calls. For high-traffic patterns, read caching strategies for high traffic sites.
Scheduled tasks that rebuild cache proactively can smooth traffic spikes. Warm popular keys after deploy:
/* app/Console/Kernel.php or routes/console.php */
Schedule::command('cache:warm-homepage')->hourly(); I register a custom Artisan command that hits internal endpoints or calls service classes directly to populate Redis before peak hours. On Nepal-facing sites, that often means warming caches before 10 AM NPT when traffic rises.
Atomic locks for cache stampede
When a popular key expires, many requests may hit the database at once. Laravel's cache lock prevents that:
$lock = Cache::lock('compute:featured-products', 10);
if ($lock->get()) {
try {
$products = Product::featured()->get();
Cache::put('featured-products', $products, 3600);
} finally {
$lock->release();
}
} The Redis distributed locks pattern explains the underlying concept. Laravel abstracts it, but you still need sensible lock TTLs.
Testing cache behaviour
In tests, use the array cache driver via phpunit.xml:
<env name="CACHE_STORE" value="array"/> Feature tests should assert that updating a model clears or refreshes the relevant cache key. Cache bugs are silent until production traffic exposes them. Pair this with Laravel feature testing best practices for CI pipelines that run on GitLab CI or GitHub Actions.
If you need to inspect serialised cache payloads during debugging, paste JSON fragments into the JSON formatter tool to readable structure—faster than dumping raw Redis strings in tinker.
Local development workflow
Never run config:cache locally unless you are reproducing a production bug. Standard local workflow:
php artisan optimize:clear That single command clears config, route, view, event, and compiled caches. Run it after pulling branch changes that touch routes or config.
For API-heavy apps, combine data caching with sensible HTTP cache headers on read-only endpoints. The Laravel API best practices guide covers ETag and Cache-Control headers that reduce origin load even when Redis is warm.
Enterprise apps with complex modules may centralise cache key constants in a dedicated class or service provider. See Laravel service providers explained for registering a singleton that wraps cache access with your naming convention.
When performance still falls short after all four layers are tuned, speed optimisation work usually shifts to asset delivery, database indexes, and CDN configuration—not more aggressive TTLs that serve stale business data.
Key Takeaways
- Run
config:cache,route:cache, andview:cacheon every production deploy after symlink swap and PHP-FPM reload. - Never call
env()outside config files once config is cached—useconfig('app.key')instead. - Use Redis 8.10 as the default data cache store; separate DB indexes for cache, session, and queue.
- Wrap expensive queries in
Cache::remember()with namespaced keys and tag-based invalidation on writes. - Match cache type to content: view cache for Blade, data cache for queries, response cache only for anonymous static HTML.
- Clear boot caches on rollback and restart queue workers so no process serves stale compiled bootstrap files.
People Also Ask
Does Laravel route caching work with closure routes?
No. Laravel route caching serialises named routes to controllers and invokable classes only. Closure-based routes cause an exception when you run route:cache. Move closure logic to controller methods before enabling route cache in production.
What is the difference between config:cache and optimize?
php artisan optimize runs config, event, route, and view caching together in Laravel 12+. Individual commands still exist when you need granular control during debugging. Use optimize:clear to wipe all compiled bootstrap files at once.
Can I use the same Redis instance for cache and sessions?
Yes, but use different Redis database numbers via REDIS_CACHE_DB and REDIS_SESSION_DB in .env. That prevents cache:clear from flushing active user sessions and makes monitoring easier.
How long should I set cache TTL for database queries?
Match TTL to business tolerance for stale data. Product catalogues often use 15–60 minutes. User permissions might use 5 minutes or event-driven invalidation. Financial or inventory-critical data should use short TTLs plus explicit flush on update, not long rememberForever() calls.
Ship Faster Laravel Apps With the Right Cache Layers
Laravel caching strategies: config, route, view, and data are not optional extras for production—they are baseline infrastructure. Config and route caches cut boot time on every request. View cache removes Blade compilation overhead. Data cache in Redis protects your MySQL or PostgreSQL tier under load. Wire all four into your deploy script, invalidate deliberately, and measure TTFB before and after.
If you want help auditing cache configuration on an existing app or building deploy automation from scratch, review the Court Marriage In Nepal and other portfolio projects for production Laravel work, or reach out via contact us to discuss your stack. For ongoing performance work after launch, support and maintenance keeps cache strategies current as Laravel and PHP versions evolve.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

