Le code fonctionne en local, le déploiement s'est bien passé, et pourtant en production une clé d'API arrive vide parce que env('MA_CLE') renvoie null, ou une page que vous venez d'ajouter répond 404 alors que sa route est bien dans routes/web.php. Dans les deux cas, la cause est la même : les caches que Laravel construit au déploiement, celui de la configuration et celui des routes. La bonne réponse n'est pas de les désactiver, mais d'écrire le code pour qu'il fonctionne avec eux, et de les reconstruire au bon moment.
Pourquoi env() renvoie null après config:cache ?
php artisan config:cache regroupe tous les fichiers de config/ dans un seul fichier, bootstrap/cache/config.php. Une fois ce cache en place, la documentation de Laravel est claire : le fichier .env n'est plus chargé, ni pendant les requêtes ni pendant les commandes Artisan. env() ne renvoie alors que les variables d'environnement définies au niveau du système, et null pour celles qui ne sont que dans .env.
Nous l'avons reproduit sur une application neuve, avec PILOT_VAR=bonjour dans .env, ce fichier de configuration et une route de test :
// config/pilot.php return [ 'var' => env('PILOT_VAR'), ];
// routes/web.php Route::get('/pilot-env', function () { return response()->json([ 'env' => env('PILOT_VAR'), 'config' => config('pilot.var'), 'external' => env('EXT_VAR'), ]); });
EXT_VAR est une variable définie au lancement du serveur PHP, pas dans .env. Résultat :
| Appel dans la route | Sans cache | Après config:cache |
|---|---|---|
env('PILOT_VAR') |
"bonjour" |
null |
config('pilot.var') |
"bonjour" |
"bonjour" |
env('EXT_VAR') |
"systeme" |
"systeme" |
La valeur n'a pas disparu : elle a été lue au moment du config:cache et figée dans la configuration. C'est env() appelé en dehors de config/ qui ne la trouve plus.
Comment corriger : env() dans config/, config() partout ailleurs
La règle de la documentation tient en une ligne : n'appeler env() que dans les fichiers de config/, et lire les valeurs avec config() partout ailleurs (contrôleurs, services, jobs, vues). Pour une clé d'API :
// config/services.php 'meteo' => [ 'key' => env('METEO_API_KEY'), ],
// Partout ailleurs dans l'application $key = config('services.meteo.key');
Après config:cache, env('METEO_API_KEY') renvoie null et config('services.meteo.key') renvoie bien la clé.
L'ancien réflexe, lancer php artisan config:clear pour "réparer", supprime le fichier de cache : env() refonctionne, mais l'application perd le cache et le problème revient au déploiement suivant. La documentation recommande au contraire de lancer config:cache à chaque déploiement en production, et de ne pas le faire en développement local.
Le cache ne relit pas .env. Dans notre test, passer PILOT_VAR à au-revoir n'a rien changé tant que php artisan config:cache n'avait pas été relancé. Après chaque modification du .env sur le serveur, il faut reconstruire le cache, y compris pour un réglage comme la durée de conservation des logs.
Pourquoi une nouvelle route répond 404 après un déploiement ?
php artisan route:cache enregistre toutes les routes dans bootstrap/cache/routes-v7.php, et c'est ce fichier qui est chargé à chaque requête. Une route ajoutée après sa création reste inconnue tant qu'il n'est pas reconstruit ou supprimé : c'est le cas d'un déploiement qui copie le nouveau code sans relancer route:cache.
Dans notre test, une route /nouvelle-page ajoutée après route:cache répond 404, et php artisan route:list --path=nouvelle ne la trouve pas. Après php artisan route:clear, elle répond 200. Après un nouveau php artisan route:cache, elle répond toujours 200, puisqu'elle fait désormais partie du cache.
cache:clear vide-t-il le cache des routes ?
Non. php artisan cache:clear vide le cache applicatif, celui que vous remplissez avec Cache::put() ou Cache::remember(). Il ne touche ni à bootstrap/cache/config.php ni à bootstrap/cache/routes-v7.php : après un cache:clear, notre route restait en 404 et env() renvoyait toujours null.
| Commande | Effet |
|---|---|
config:cache / config:clear |
crée / supprime le cache de la configuration |
route:cache / route:clear |
crée / supprime le cache des routes |
cache:clear |
vide le cache applicatif, rien d'autre |
optimize |
met en cache la configuration, les événements, les routes et les vues |
optimize:clear |
supprime ces caches, les fichiers compilés et vide aussi le cache applicatif |
Pour savoir où en est un serveur, php artisan about --only=cache affiche CACHED ou NOT CACHED pour la configuration, les événements, les routes et les vues.
Dans quel ordre lancer les commandes au déploiement ?
php artisan optimize enchaîne config:cache, event:cache, route:cache et view:cache. Il doit passer une fois le nouveau code et le .env définitif en place, sinon il fige l'état précédent. Voici la séquence que nous avons exécutée de bout en bout :
# Une fois le nouveau code récupéré (git pull ou équivalent) composer install --no-dev --optimize-autoloader php artisan migrate --force php artisan optimize php artisan reload
php artisan reload relance les services qui tournent en continu (dans notre test, les workers de file d'attente et le planificateur) pour qu'ils utilisent le nouveau code. Si l'application affiche des fichiers envoyés par ses utilisateurs, vérifiez aussi le lien public/storage. En cas de doute sur un serveur, php artisan optimize:clear repart de zéro et php artisan optimize reconstruit tout ; gardez en tête que optimize:clear vide aussi le cache applicatif.
Ce sont des réglages que nous mettons en place sur les applications que nous hébergeons et maintenons, comme sur les applications sur mesure que nous développons. Un déploiement qui casse en production ? Parlons-en.
env()seulement dansconfig/,config()partout ailleurs.- Garder
config:cache(ouoptimize) en production, et le relancer après chaque modification du.env. - Une route en 404 après un déploiement :
route:clearou un nouveauroute:cache, jamaiscache:clear. - Au déploiement : code, dépendances, migrations, puis
php artisan optimizeetphp artisan reload.
Testé avec Laravel 13.37.0 et PHP 8.3.6.
Questions fréquentes
Faut-il lancer config:cache en développement local ?
Non. La documentation de Laravel le réserve au déploiement en production : en local, les options de configuration changent souvent et le cache obligerait à le reconstruire à chaque modification.
env() lit-il encore les variables définies par le serveur après config:cache ?
Oui. Une fois la configuration en cache, env() ne renvoie plus que les variables d'environnement du système. Dans notre test, une variable passée au lancement du serveur PHP restait lisible, alors que celle du .env renvoyait null.
Comment vérifier qu'une route fait partie du cache ?
php artisan route:list --path=... lit le cache quand il existe. Si la route n'y apparaît pas alors qu'elle est dans routes/web.php, le cache est périmé : relancez php artisan route:cache.
Les routes définies avec une closure peuvent-elles être mises en cache ?
Oui. Dans notre test sous Laravel 13, des routes déclarées avec une closure ont été mises en cache par route:cache et servies normalement.