The simplest 30ms you'll ever save.
Route caching is a single command that can reduce your request time by 20-40ms. It's the lowest-hanging fruit in Laravel performance tuning. Yet 90% of production Laravel apps don't have it enabled.
On every single HTTP request, Laravel:
routes/web.php (and routes/api.php)Route::get(), Route::post(), etc./users/{id} β #^/users/([^/]+)$#)// routes/web.php β 200+ routes is normal for a medium app
Route::get('/', [HomeController::class, 'index']);
Route::get('/users', [UserController::class, 'index']);
Route::get('/users/{id}', [UserController::class, 'show']);
Route::post('/users', [UserController::class, 'store']);
Route::put('/users/{id}', [UserController::class, 'update']);
Route::delete('/users/{id}', [UserController::class, 'destroy']);
Route::get('/posts', [PostController::class, 'index']);
Route::get('/posts/{slug}', [PostController::class, 'show']);
// ... 190 more routes with complex regex patterns
For 200 routes: ~20-35ms of CPU time per request β just to figure out which controller to call. Multiply by 1 million requests per day = 20,000 seconds of wasted CPU daily.
That's it. One command. Run it after you deploy your code.
// bootstrap/cache/routes-v7.php (generated file β DO NOT EDIT)
<?php return array (
'GET' =>
array (
'/' =>
array (
'uses' => 'App\\Http\\Controllers\\HomeController@index',
'middleware' => array (),
),
'/users' =>
array (
'uses' => 'App\\Http\\Controllers\\UserController@index',
'middleware' => array (),
),
'/users/{id}' =>
array (
'uses' => 'App\\Http\\Controllers\\UserController@show',
'where' =>
array (
'id' => '[0-9]+',
),
),
// ... all 200 routes, precompiled as a PHP array
),
'POST' =>
array (
'/users' =>
array (
'uses' => 'App\\Http\\Controllers\\UserController@store',
),
),
);
Instead of parsing regex and reading files on every request, Laravel now just require()s a precompiled PHP array. No regex. No file parsing. No I/O per request.
| Routes parsed per request | 200 |
| Regex operations | 200+ |
| File I/O operations | ~10 |
| Time per request (parsing only) | 25-35ms |
| Routes parsed per request | 1 (the cached array) |
| Regex operations | 0 |
| File I/O operations | 1 |
| Time per request (parsing only) | 1-3ms |
| Metric | Without Cache | With Cache | Improvement |
|---|---|---|---|
| CPU time per request (route matching) | 30ms | 2ms | 93% β |
| File I/O operations | 10-20 | 1 | 90% β |
| Memory per request | ~2MB (temporary) | ~0.1MB (from cache) | 95% β |
| 10,000 requests per day | 300 seconds (5 minutes of CPU) | 20 seconds | 280 seconds saved daily |
This single command runs:
php artisan route:cache β caches routesphp artisan config:cache β caches configurationphp artisan event:cache β caches event listenersphp artisan view:cache β precompiles Blade templatesRun php artisan optimize:clear before deployment, then php artisan optimize after deployment.
If you add a new route or change a config file, Laravel will still use the old cached version until you clear it. Always re-run optimize after any change in:
routes/ directory (any file)config/ directory (any file)app/Listeners/ directory (event listeners)resources/views/ (Blade templates β but view cache is less critical)Add this to your deployment script (CI/CD):
#!/bin/bash
# deploy.sh
php artisan down --retry=60
git pull origin main
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan optimize # β This is critical
php artisan up
Never deploy without php artisan optimize. Never.
| Concept | Without Cache | With Cache |
|---|---|---|
| What Laravel does | Parses 200+ routes with regex per request | Loads precompiled PHP array |
| Time cost | 25-35ms per request | 1-3ms per request |
| When to run | Never | After every deployment, after any route change |
| Command | β | php artisan route:cache or php artisan optimize |
php artisan optimize.Topic 3: Config Caching β The env() trap that kills your config cache. Why config() is your best friend and env() is your enemy in production.