Config, Route and View Caches

What config:cache, route:cache and view:cache freeze, and why env() returns null once configuration is cached.

Syntaxphp artisan optimize # config:cache + event:cache + route:cache + view:cache

These caches have nothing to do with the Cache facade. They are build artefacts, written once at deploy time, that let the framework skip work it would otherwise repeat on every request.

What each one freezes

CommandWhat it freezes
config:cacheEvery file in config/, merged into one file under bootstrap/cache. The .env file is then no longer loaded.
route:cacheAll route registrations, reduced to a single cached file.
view:cacheEvery Blade template, precompiled instead of compiled on first use.
event:cacheThe auto-discovered event to listener mappings.

php artisan optimize is the shorthand for all four; the longhand is config:cache, event:cache, route:cache, view:cache. Each has a matching :clear command, and php artisan optimize:clear removes all of them. Note that optimize:clear also flushes the keys in your default cache store, so it is the wrong tool for a stale template.

The env() that returns null

Once configuration is cached, .env is not read at all. env() called anywhere outside config/ returns null: a class that reads env('SHIPPING_KEY') works locally and gets null in production. Read values through config('shipping.key') and let the config file be the only place env() appears.

Route caching serializes your routes, and a closure cannot be serialized. A route written as Route::get('/x', function () { ... }) fails the command; move it into a controller. Route::view() and Route::redirect() are backed by framework controllers, so they cache without complaint.

Example

Example · php
<?php
// config/shipping.php

// env() is safe here. Config files are the only code read while the
// config cache is being built, so this is where .env values enter.
return [

    'base_url' => env('SHIPPING_BASE_URL', 'https://api.example.test'),

    'key' => env('SHIPPING_KEY'),

    'timeout' => (int) env('SHIPPING_TIMEOUT', 5),

];

When to use it

  • Cut per-request filesystem work on a deployed application.
  • Explain why a new .env value is null in production but fine locally.
  • Find the one route closure that makes route:cache fail.
  • Write a deploy script that leaves the application cache intact.

More examples

The same value, read two ways

Two lines that behave identically on a developer machine and differently on a deployed server. The failure arrives as an authentication error from the remote API, not as an exception about configuration, which is what makes it hard to place. Grep an unfamiliar application for env( outside config/ before you trust its deployment.

Example · php
<?php
// app/Services/ShippingClient.php

declare(strict_types=1);

namespace App\Services;

class ShippingClient
{
    public function __construct(
        // Null in production as soon as config:cache has run.
        private ?string $wrong = null,
        private ?string $right = null,
    ) {
        $this->wrong = env('SHIPPING_KEY');

        $this->right = config('shipping.key');
    }
}

A closure that blocks route:cache

Route caching is usually introduced late, when the route file is already long, so the error names one route out of hundreds. Keeping route files free of closures from the start means route:cache is never a migration project.

Example · php
// routes/web.php

// Fails route:cache: the closure cannot be serialized.
Route::get('/health', function () {
    return response()->json(['ok' => true]);
});

// Caches cleanly: a controller is a class name and a method name.
Route::get('/health', [HealthController::class, 'show']);

// These are fine too. Both are framework controllers underneath.
Route::view('/about', 'pages.about');
Route::redirect('/old', '/new');

Where these commands belong in a deploy

Run optimize after the new code is in place, never before. Prefer it to optimize:clear here: optimize overwrites the four build caches, while optimize:clear would also empty your application cache and leave the first visitors to rebuild every cached value.

Example · bash
php artisan down --render="errors::503"

composer install --no-dev --optimize-autoloader
php artisan migrate --force

# Rewrites the config, event, route and view caches in place.
php artisan optimize

# Terminates long-running services so they pick up the new code.
php artisan reload

php artisan up

Discussion

  • Be the first to comment on this lesson.