php artisan config:clear looks like housekeeping. It deletes bootstrap/cache/config.php so Laravel will read fresh config files on the next request. That is the right thing to do in development, but in production it is the first half of a two-step operation that leaves your app temporarily slower and potentially inconsistent if the second half never finishes.
The problem starts when a deploy script runs config:clear, then fails during config:cache. Production is now serving uncached config. Every request parses every config file, runs every env() call, and regenerates the application configuration. Boot time goes up. If your deploy runs across multiple servers, one node may rebuild its cache while another stays cleared. Monitoring config:clear turns a silent failure into a deploy event you can check.
How config:clear works
When you run:
php artisan config:clear
Laravel calls Illuminate\Foundation\Console\ConfigClearCommand, which deletes the cached config file at bootstrap/cache/config.php. That is it. No rebuild. No validation. It removes the cache so the framework reads files on every boot instead.
Most production deploy scripts pair it with config:cache:
php artisan config:clear
php artisan config:cache
If the first step succeeds and the second fails, your app is live but running without its config cache. The deploy script may not catch the failure because the exit code from config:clear was zero.
Common failure modes
The cache is cleared but never rebuilt. A deploy script clears the old config, a later step or package fails, and the script either stops or quietly carries on. Production now boots slower and processes more filesystem reads per request. This is the most common config:clear failure in production because the app keeps working and nobody checks whether the cache exists.
A rolling deploy creates mixed config states. In a multi-server setup, one node may clear its config cache, another may still have the old cache, and a third may have rebuilt with the new release. Users see different values for the same config key depending on which server handles the request. Database credentials, queue connections, and API keys can be wrong on some requests and correct on others.
Permission errors leave the old cache in place. If the deploy user cannot write to bootstrap/cache, config:clear may fail silently without deleting the file. The app keeps serving the old cached config. New environment values added in .env never take effect, and the deploy looks successful because the app never crashed.
A cleared cache hides stale config from one server. If you deploy to multiple hosts and only one runs config:clear before the code sync finishes, that host serves uncached config from the new release while the others serve cached config from the previous release. The difference in boot time and available config values makes behavior hard to reproduce in debugging.
Building visibility into config:clear
Treat config cache clearing as a deploy event that needs verification. Fail the deploy script immediately if either step doesn’t leave the expected cache state:
#!/usr/bin/env bash
set -euo pipefail
cd /var/www/current
php artisan config:clear
# Confirm the cache file is gone
test ! -f bootstrap/cache/config.php
php artisan config:cache
# Confirm the rebuild actually produced a file
test -s bootstrap/cache/config.php
That catches the command failing on the node running the deploy. It does not catch a node that never ran the deploy step, or a rebuild that failed silently after the clear succeeded - for that, schedule a periodic check.
For quick verification during a manual run:
php artisan config:clear
php artisan config:show app.name > /dev/null
The second command forces Laravel to boot and read config files. If a config file has a syntax error, this is where you see it rather than when users hit the app.
Detecting when config:clear fails
Check three things:
- Did the file actually get deleted?
test ! -f bootstrap/cache/config.phpafter the command catches silent permission failures. - Did the command run on every server? Query the health endpoint below per host to see which nodes reported the expected state.
- Did the rebuild follow? Without confirming
config:cacheafterward, the cleared state persists and your app runs uncached.
A quick endpoint on each server shows the current cache state:
Route::get('/_deploy/config-status', function () {
return response()->json([
'host' => gethostname(),
'release' => trim(@file_get_contents(base_path('REVISION'))),
'config_cached' => file_exists(base_path('bootstrap/cache/config.php')),
'config_cache_mtime' => file_exists(base_path('bootstrap/cache/config.php'))
? filemtime(base_path('bootstrap/cache/config.php'))
: null,
]);
})->middleware('auth.basic');
Call this after every deploy. If one host reports config_cached: false when all others report true, that server needs attention before it can serve traffic safely.
Quick setup with Crontinel
Wrap the deploy-window verification above in a scheduled command:
// routes/console.php
Schedule::call(function () {
if (! file_exists(base_path('bootstrap/cache/config.php'))) {
throw new RuntimeException('config cache missing - clear ran without a rebuild');
}
})->everyFiveMinutes()->name('config-cache-state-check');
Crontinel’s package hooks into ScheduledTaskStarting, ScheduledTaskFinished, and ScheduledTaskFailed automatically once installed - no ping URL or config needed. Create a Cron monitor for config-cache-state-check with an alert window that matches your deploy cadence.
If you already monitor optimize:clear, the two checks together tell the full story: the old cache was cleaned up, and the new one was built.
If you already monitor config:cache and optimize:clear, adding config:clear fills the gap. The three commands cover the most common production cache failures.