codegenie-be/laravel-config-cache-guard

Prevent Laravel from using stale config or route cache after deployment changes, with Composer autoload integration and in-app auto repair for shared hosting.

Maintainers

Package info

github.com/Codegenie-BE/laravel-config-cache-guard

pkg:composer/codegenie-be/laravel-config-cache-guard

Transparency log

Statistics

Installs: 22

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0


README

Tests Latest Version on Packagist Total Downloads License: MIT PHP Laravel

by Codegenie

Prevent Laravel from running with stale cached configuration or stale cached routes after .env, config/*.php or routes/*.php changes.

Built for Laravel 12 and 13 apps on shared hosting, FTP deployments and simple production setups where php artisan config:cache or php artisan route:cache can accidentally be forgotten.

This package is a safety net. The best production flow is still to rebuild Laravel deployment caches during deployment.

Quick start

composer require codegenie-be/laravel-config-cache-guard
php artisan config-cache-guard:status

No public/index.php change is required. The guard is loaded automatically by Composer when Laravel requires vendor/autoload.php, before bootstrap/app.php bootstraps the application.

Why this exists

Laravel can cache configuration into:

bootstrap/cache/config.php

Laravel can also cache routes into files such as:

bootstrap/cache/routes-v7.php

Those caches are good for production performance, but they also mean changes in .env, config/*.php or routes/*.php are not reflected until the relevant cache is rebuilt.

This is easy to forget on shared hosting, FTP deployments or hosting panels where deploy hooks are limited. This package checks whether source metadata changed before Laravel bootstraps. If it changed, it prevents Laravel from using stale deployment cache and tries to rebuild safely.

When shell functions such as exec() are disabled, the package removes stale config cache, points Laravel at a current signature-based route cache path, and queues an internal in-app auto repair. After the current HTTP response is sent, the package can rebuild through Laravel's own Artisan::call() without SSH, tokens or public repair URLs.

What it does

On normal HTTP requests, the guard performs small metadata checks against:

  • .env
  • .env.{APP_ENV} when APP_ENV is provided as a real server environment variable
  • config/**/*.php when config cache guarding is active
  • routes/**/*.php when a route cache file already exists
  • bootstrap/app.php when it exists, because modern Laravel apps often register routes there
  • app/Providers/RouteServiceProvider.php when it exists

It only checks file metadata such as timestamps, file size and inode metadata. It does not read or store secret values.

By default, config cache guarding refreshes an existing bootstrap/cache/config.php file. It does not force config caching on projects that are not using config cache. You can opt into creating config cache when missing with CONFIG_CACHE_GUARD_CREATE_CONFIG_CACHE=true.

When the config signature changed and config cache exists, the guard takes a file lock and tries:

php artisan config:cache

When the route signature changed and a route cache file already exists, the guard takes a file lock and tries:

php artisan route:cache

If pre-bootstrap rebuilding cannot run because exec() or a PHP CLI binary is unavailable, stale config cache is removed and stale route cache is bypassed with a signature-based route cache path. An internal pending marker is written, then the service provider processes that marker with Artisan::call() after the current HTTP response is sent.

What it does not do

  • It does not read, log or store .env values.
  • It does not use Redis, queues, workers, cron or a database.
  • It does not require you to manually register middleware.
  • It does not expose an unauthenticated public repair endpoint.
  • It does not require a secret repair token for automatic in-app repair.
  • It does not rebuild config cache or route cache on every request.
  • It does not automatically start route caching when your app is not already using route cache.
  • It does not run cache:clear, optimize:clear, view:clear or event:clear.
  • It does not replace a proper deployment process.

The pre-bootstrap guard is loaded through Composer autoload.files. The package service provider only registers Artisan commands and schedules internal pending repair markers to run after the current HTTP response is sent.

When to use this package

Use it when:

  • you deploy Laravel through FTP or shared hosting
  • your deploy process sometimes forgets php artisan config:cache or php artisan route:cache
  • your hosting panel has limited deployment hooks
  • your hosting disables exec(), SSH or direct command access
  • you want a small safety net against stale config cache or stale route cache
  • you want to avoid queues, Redis, cron or background workers

Do not use it as a replacement for a correct deployment pipeline.

How it works

HTTP request
  -> public/index.php
  -> Laravel requires vendor/autoload.php
  -> Composer autoloads the pre-bootstrap guard
  -> guard checks config and route source metadata
  -> unchanged: continue immediately
  -> changed config: remove stale config cache before Laravel can use it
  -> changed routes: point Laravel at a current signature-based route cache path
  -> exec/PHP CLI available: run config:cache or route:cache before Laravel boots
  -> exec/PHP CLI unavailable: write pending repair marker
  -> Laravel boots without stale deployment cache
  -> current request continues without stale deployment cache
  -> after the response is sent, service provider processes pending marker with Artisan::call()
  -> next request uses the refreshed cache file

This order is important. A Laravel middleware or normal service provider is too late to prevent Laravel from loading old cached config or old cached routes. The Composer-loaded guard prevents stale cache from being used. The in-app auto repair fallback only runs after the current response is sent, so Laravel's in-request view, session and routing state is not disturbed by cache rebuild commands.

Installation

composer require codegenie-be/laravel-config-cache-guard
php artisan config-cache-guard:status

That is enough for normal Laravel projects. No manual require line is needed in public/index.php.

Upgrading from older versions

Older versions asked you to add a manual require line to public/index.php:

require __DIR__ . '/../vendor/codegenie-be/laravel-config-cache-guard/bootstrap/guard.php';

That line is now legacy. It is safe because the guard is idempotent, but it is no longer needed.

Remove it manually, or run:

php artisan config-cache-guard:install --remove-legacy

A dry run is available:

php artisan config-cache-guard:install --remove-legacy --dry-run

Status check

php artisan config-cache-guard:status

This checks:

  • whether Composer autoload integration is active
  • whether a legacy public/index.php require line still exists
  • whether the guard is enabled
  • whether the config guard is enabled
  • whether the route guard is enabled
  • whether the in-app auto repair fallback is enabled
  • which failure cooldown is configured
  • whether fail-hard mode is enabled
  • whether bootstrap/cache is writable
  • whether cached config exists
  • whether cached routes exist
  • whether the config and route signature files exist
  • whether pending repair markers exist and why
  • whether failed-rebuild markers exist and why
  • when config and route cache repair last succeeded
  • which active cache files are currently expected
  • how many stale route cache files were cleaned during the last successful route repair
  • whether exec() is available
  • which PHP CLI binary will be used

Clear old failure and pending markers after fixing a hosting issue:

php artisan config-cache-guard:status --clear-failures

Requirements

  • PHP 8.2 or higher
  • Laravel 12 or 13
  • A writable bootstrap/cache directory
  • Optional: exec() and a working PHP CLI binary for pre-bootstrap rebuilding

When exec() is unavailable, the in-app auto repair fallback can still rebuild through Artisan::call() after the current response is sent.

Compatibility

Laravel Package target PHP range Framework status
12 Supported 8.2 - 8.5 Security fixes until February 24, 2027
13 Supported 8.3 - 8.5 Security fixes until March 17, 2028

PHP 8.2 is security fixes only until December 31, 2026. For new production projects, prefer PHP 8.4 or PHP 8.5 when your hosting supports it.

Useful references:

Environment options

Pre-bootstrap options should preferably be real server environment variables because the guard runs before Laravel bootstraps.

Variable Default Description
CONFIG_CACHE_GUARD_ENABLED true Set to false, 0, off or no to disable the entire guard.
CONFIG_CACHE_GUARD_CONFIG true Set to false, 0, off or no to disable config cache guarding only.
CONFIG_CACHE_GUARD_ROUTES true Set to false, 0, off or no to disable route cache guarding only.
CONFIG_CACHE_GUARD_CREATE_CONFIG_CACHE false Set to true to let the guard create bootstrap/cache/config.php even when no config cache exists yet.
CONFIG_CACHE_GUARD_AUTO_REPAIR true Allows the service provider to process pending repair markers through Artisan::call() after the current HTTP response is sent.
CONFIG_CACHE_GUARD_AUTO_REFRESH true Redirects normal GET/HEAD browser requests if a route repair was completed before dispatch. In the default deferred repair flow, the current request already runs without stale route cache.
CONFIG_CACHE_GUARD_VERSIONED_ROUTE_CACHE true Stores refreshed route caches in a signature-based routes-*.php file and sets APP_ROUTES_CACHE before Laravel boots. This avoids stale opcache reads of routes-v7.php on shared hosting.
CONFIG_CACHE_GUARD_FAILURE_COOLDOWN 60 Number of seconds to wait after a failed rebuild before trying again.
CONFIG_CACHE_GUARD_FAIL_HARD false Show a safe 503 error page when pre-bootstrap refresh cannot continue. Leave this false when you want in-app auto repair to run automatically.
CONFIG_CACHE_GUARD_PHP_BINARY auto-detect Optional full path to the PHP CLI binary.
PHP_CLI_BINARY auto-detect Secondary PHP CLI binary override.
APP_ROUTES_CACHE Laravel default Optional Laravel route cache path override. Explicit custom paths are respected; guard-managed signature paths are only used when no custom path is configured.
APP_ENV optional When provided externally, .env.{APP_ENV} is included in metadata signatures.

Example:

CONFIG_CACHE_GUARD_ENABLED=true
CONFIG_CACHE_GUARD_CONFIG=true
CONFIG_CACHE_GUARD_ROUTES=true
CONFIG_CACHE_GUARD_AUTO_REPAIR=true
CONFIG_CACHE_GUARD_FAILURE_COOLDOWN=60
CONFIG_CACHE_GUARD_PHP_BINARY=/usr/bin/php

Shared hosting without exec

Some shared hosts disable exec(). In that case, the pre-bootstrap guard cannot start php artisan config:cache or php artisan route:cache as a CLI command before Laravel boots.

This package handles that without a public endpoint:

1. stale config cache is removed immediately
2. stale route cache is bypassed by pointing Laravel at a signature-based route cache path
3. a safe pending marker is written
4. Laravel boots without using the stale route cache
5. the current request continues without stale deployment cache
6. after the response is sent, the service provider rebuilds through Artisan::call()
7. the next request uses the refreshed cache file

If the in-app repair fails, a safe .failed marker is written in bootstrap/cache. It contains a reason and suggested action, but no .env values, secrets, tokens or command output.

Files written by the guard

The guard may create or update these files inside bootstrap/cache:

File Purpose
config.php Laravel's cached configuration, created by php artisan config:cache.
config-source.signature Metadata signature of .env and config/**/*.php.
config-cache-refresh.lock File lock to avoid concurrent config cache rebuilds.
config-cache-refresh.pending Internal marker used by the in-app auto repair fallback.
config-cache-refresh.failed Safe diagnostic marker after a failed config rebuild attempt.
config-cache-refresh.succeeded Safe diagnostic marker after a successful config rebuild.
routes-*.php Laravel's cached routes, created by php artisan route:cache.
route-source.signature Metadata signature of route source files.
route-cache-refresh.lock File lock to avoid concurrent route cache rebuilds.
route-cache-refresh.pending Internal marker used by the in-app auto repair fallback.
route-cache-refresh.failed Safe diagnostic marker after a failed route rebuild attempt.
route-cache-refresh.succeeded Safe diagnostic marker after a successful route rebuild, including stale route cleanup count.

Failure behavior

Situation Behavior
No relevant source change Continue immediately.
No config cache exists and CONFIG_CACHE_GUARD_CREATE_CONFIG_CACHE=false Do nothing for config cache.
Config changed and pre-bootstrap rebuild succeeds Continue with refreshed cached config.
Routes changed and pre-bootstrap rebuild succeeds Continue with refreshed cached routes in the current signature-based route cache file.
Config rebuild needs exec() but exec() is disabled Remove stale cached config and write a pending auto repair marker.
Route rebuild needs exec() but exec() is disabled Point Laravel at the current signature-based route cache path, keep older bypassed route cache files for cleanup, and write a pending auto repair marker. If a signature-based bypass is not possible, remove the stale route cache file so the current request loads route source files.
PHP CLI is not found Use the same pending auto repair fallback behavior for the affected cache target.
Pre-bootstrap rebuild fails Use the same pending auto repair fallback behavior for the affected cache target.
In-app auto repair succeeds Rebuild through Laravel without exec() after the current response is sent, update signatures and remove pending markers.
In-app auto repair fails Remove stale cache file and write a safe failed marker.

Removing stale config cache files is intentional. For routes, the guard avoids stale reads by switching Laravel to a route-cache filename derived from the current route source signature. Explicit custom APP_ROUTES_CACHE paths are respected; if a custom route cache is stale and cannot be rebuilt before boot, the stale file is removed and rebuilt at the same custom path after the response. Running uncached for one request is slower, but safer than continuing with old configuration or old routes.

Testing manually

After installation, you can test the config guard like this:

php artisan config:cache
php artisan config-cache-guard:status

Then change a value in a file such as config/app.php or update its modified time:

touch config/app.php

Load the application once in the browser. If exec() and PHP CLI are available, the guard should rebuild bootstrap/cache/config.php and update bootstrap/cache/config-source.signature.

If exec() is disabled, the first request removes the stale config cache and queues in-app auto repair after the response. A following request should use the refreshed config cache if the repair succeeded.

To test the route guard, first make sure your app already uses route cache:

php artisan route:cache
php artisan config-cache-guard:status

Then change a route file or update its modified time:

touch routes/web.php

Load the application once in the browser. If exec() and PHP CLI are available, the guard should rebuild bootstrap/cache/routes-*.php and update bootstrap/cache/route-source.signature.

If exec() is disabled, the first request points Laravel at a signature-based route cache path and queues in-app auto repair after the response. A following request should use the refreshed route cache if the repair succeeded.

Recommended production flow

Use this package as a fallback, not as your primary deployment strategy.

A solid deployment should still include:

php artisan config:cache
php artisan route:cache

Only run php artisan route:cache in deployments when your application supports Laravel route caching.

This package protects you when those steps are forgotten, skipped or not available on shared hosting.

Known limitations

  • Pre-bootstrap rebuilding requires exec() and a working PHP CLI binary.
  • In-app auto repair works without exec(), but it runs after the current HTTP response is sent. The current request runs without stale deployment cache first.
  • CONFIG_CACHE_GUARD_FAIL_HARD=true intentionally stops the request with a safe 503 page, so in-app auto repair cannot run during that same request.
  • Change detection is metadata-based for performance. It uses file timestamps, size and inode metadata instead of reading file contents or .env values.
  • Config cache creation when missing is opt-in through CONFIG_CACHE_GUARD_CREATE_CONFIG_CACHE=true.
  • Route cache guarding only activates automatically when a bootstrap/cache/routes-*.php file already exists.
  • The package does not clear application cache, view cache, event cache, OPcache or Redis.
  • This package is a fallback safety net. It should not replace a correct deployment pipeline that runs Laravel's deployment cache commands.

Troubleshooting

The status command says exec available: no

Your hosting disables exec(). The guard can still remove stale cached config and bypass stale cached routes. With CONFIG_CACHE_GUARD_AUTO_REPAIR=true, it can then rebuild through Artisan::call() after the current HTTP response is sent.

I see config-cache-refresh.pending or route-cache-refresh.pending

A stale cache target was handled and the package queued an in-app repair. Load the application once more, then run:

php artisan config-cache-guard:status

If the pending marker remains, check whether Laravel can run the relevant cache command.

I see config-cache-refresh.failed or route-cache-refresh.failed

Open the file. It contains a safe diagnostic reason and suggested action. It does not contain .env values, secrets, tokens or command output.

After fixing the issue, clear old markers:

php artisan config-cache-guard:status --clear-failures

Or remove them manually from bootstrap/cache.

public/index.php still contains the old require line

Current versions do not need this line anymore:

require __DIR__ . '/../vendor/codegenie-be/laravel-config-cache-guard/bootstrap/guard.php';

Remove it manually, or run:

php artisan config-cache-guard:install --remove-legacy

The wrong PHP binary is detected

Set the binary manually:

CONFIG_CACHE_GUARD_PHP_BINARY=/usr/bin/php

Then run:

php artisan config-cache-guard:status

I do not want in-app auto repair

Disable only the in-app fallback:

CONFIG_CACHE_GUARD_AUTO_REPAIR=false

I do not want route cache guarding

Disable only route cache guarding with a real server environment variable:

CONFIG_CACHE_GUARD_ROUTES=false

I want to disable the guard temporarily

Use a real server environment variable:

CONFIG_CACHE_GUARD_ENABLED=false

Uninstall

Remove the package:

composer remove codegenie-be/laravel-config-cache-guard

If you installed an older version that added a manual require line to public/index.php, remove it too:

require __DIR__ . '/../vendor/codegenie-be/laravel-config-cache-guard/bootstrap/guard.php';

Optional cleanup:

rm -f bootstrap/cache/config-source.signature
rm -f bootstrap/cache/config-cache-refresh.lock
rm -f bootstrap/cache/config-cache-refresh.pending
rm -f bootstrap/cache/config-cache-refresh.failed
rm -f bootstrap/cache/route-source.signature
rm -f bootstrap/cache/route-cache-refresh.lock
rm -f bootstrap/cache/route-cache-refresh.pending
rm -f bootstrap/cache/route-cache-refresh.failed

Security and privacy

This package is intentionally small and file-based.

  • It does not read .env values.
  • It does not store secrets.
  • It does not send data to external services.
  • It does not use a database.
  • It does not require Redis, queues, workers or cron.
  • It uses file locks to avoid concurrent rebuilds.
  • The automatic rebuild commands are fixed to php artisan config:cache and php artisan route:cache; paths are escaped and no user input is passed to the shell.
  • The in-app auto repair fallback uses Laravel's own Artisan::call() and does not expose command output.

Please report security issues privately. See SECURITY.md.

License

The MIT License. See LICENSE.md.

About Codegenie

Codegenie builds Laravel websites and web applications with a focus on simplicity, reliability and production-friendly deployment.

https://www.codegenie.be