Laravel no toma tu .env? El fix real del config cache
En pocas palabras: Laravel no relee tu .env porque php artisan config:cache compiló la configuración en bootstrap/cache/config.php y sirve ese snapshot en cada request. Corré php artisan config:clear (o config:cache para regenerarlo) tras el deploy y los cambios impactan al instante.
Cambiás el archivo .env en producción, recargás la página y Laravel te sigue mostrando la base de datos vieja, la URL de siempre o el mail que ya no usás. No es un bug: Laravel está leyendo un snapshot cacheado de la configuración (bootstrap/cache/config.php), y mientras ese archivo exista, tu .env nuevo lo ignora por completo. La solución pasa por regenerar ese caché, no por editar el .env otra vez.
Si alguna vez deployaste una app Laravel y quedaste mirando la pantalla sin entender por qué el cambio no impactaba, esto es para vos.
Laravel es un framework PHP que carga las variables de entorno del archivo .env a través de los archivos de configuración en config/, y cuando corrés php artisan config:cache compila todo eso en un único archivo estático que se lee en cada request. A partir de ahí, la función env() deja de leer el .env durante la ejecución. Por eso editar el .env solo no cambia nada: hay que reconstruir el snapshot.
En 30 segundos
- La causa: existe
bootstrap/cache/config.phpy Laravel usa ese snapshot en vez de tu.envactualizado. - El fix normal: corré
php artisan config:cacheDESPUÉS de subir el.envnuevo, no antes. - La regla de oro: tu código debe usar
config('database.host'), nuncaenv('DB_HOST')directo (devuelvenullcon el caché activo). - Sin SSH: en hosting compartido podés borrar
bootstrap/cache/config.phppor FTP para forzar la recarga, o pedirle a soporte que corra los comandos. - Ojo: los queue workers cachean la config al arrancar; hay que reiniciarlos aparte.
¿Por qué Laravel no lee mis cambios de .env después del deployment?
Porque existe un snapshot cacheado. Cuando corrés php artisan config:cache, Laravel junta todos los archivos de config/ (que a su vez leyeron el .env) y los compila en bootstrap/cache/config.php. Desde ese momento, el framework no vuelve a abrir el .env ni en los requests ni en los comandos Artisan. Lee el snapshot y listo. Complementá con alternativas de cloud-hosting para tu proyecto.
Según la documentación oficial de configuración de Laravel, esto es intencional: leer un solo archivo compilado es más rápido que parsear el .env y toda la carpeta config/ en cada request. En producción es lo que querés. El problema aparece cuando editás el .env y te olvidás de que ese archivo compilado sigue ahí, congelado con los valores viejos.
Ponele que cambiás DB_HOST de localhost a la IP del nuevo servidor de base de datos. Subís el .env, recargás, y la app sigue intentando conectarse a localhost. ¿Por qué? Exacto: el config.php cacheado todavía dice localhost, y hasta que no lo regeneres, ese valor manda.
Diferencia entre config() y env(): dónde deben estar tus variables
La regla es corta: tu código de aplicación tiene que leer config('database.connections.mysql.host'), nunca env('DB_HOST'). El .env alimenta los archivos de config/, y esos archivos son la única capa que tu app debería consultar. La propia documentación de Laravel recomienda llamar a env() solo desde archivos de configuración.
¿Y qué pasa si llamás env() directo desde un controlador, un job o un service? Con el caché activo, te devuelve null. Porque env() lee el archivo .env, y ese archivo ni se abre cuando existe el snapshot. Es la explicación detrás de los reportes de “env() retorna null en producción” que aparecen en las discusiones del repositorio de Laravel en GitHub.
La arquitectura correcta es así: el .env guarda los secretos y valores por entorno. Los archivos config/database.php, config/app.php, config/mail.php leen esas variables con env() y las exponen como claves de configuración. Tu código pide esas claves con config(). Cuando cacheás, se congela la capa config, no la capa env, así que mientras uses config() todo funciona.
Ejemplo concreto de por qué env() falla en caché
Tenés un PaymentController que hace $key = env('STRIPE_KEY'). En local anda perfecto porque no tenés config cacheada. Deployás, corrés config:cache, y de golpe $key es null y todos los pagos fallan. La corrección: mové ese valor a config/services.php con 'stripe' => ['key' => env('STRIPE_KEY')] y en el controlador usá config('services.stripe.key'). Ahora sí sobrevive al caché. En solucionar problemas comunes de hosting profundizamos sobre esto.
Solución normal: comandos para actualizar configuración después de deployment
El fix confiable es reconstruir el caché una vez que el código nuevo y el .env actualizado ya están en su lugar. El orden importa muchísimo: primero el .env, después los comandos. Si cacheás antes de subir el .env, congelás los valores viejos.
El flujo recomendado por la guía de deployment de Laravel es este:
- Actualizá el
.enven el servidor con todos los valores nuevos. Recién cuando esté completo pasás al siguiente paso. - Regenerá la config:
php artisan config:cache. Esto borra el snapshot viejo y compila uno nuevo con tus valores actuales. - Si usás rutas cacheadas:
php artisan route:cache. - Opcional, todo junto:
php artisan optimizecorre config, rutas y vistas de una.
Cuando corrés config:cache vas a ver un output tipo Configuration cached successfully. Ese mensaje confirma que el nuevo bootstrap/cache/config.php ya está escrito con tus valores frescos. Si no lo ves, algo falló antes (permisos, sintaxis en un archivo de config).
Checklist de deployment seguro en Laravel: evitar que .env falle
El objetivo del checklist es simple: que el .env esté completo ANTES de cachear, y validar que el valor nuevo realmente quedó. Estos son los pasos que no deberías saltear:
- Subí el
.envprimero: asegurate de que todos los cambios estén en el servidor antes de tocar ningún comando de caché. - Chequeá permisos: el
.envtiene que ser legible por el usuario de PHP, pero nunca world-writable. Unchmod 640alcanza en la mayoría de los setups. - Corré los comandos en orden:
config:cachey despuésroute:cache, nunca al revés ni antes de subir el.env. - Reiniciá PHP-FPM si hace falta: algunos setups mantienen la config vieja en memoria hasta que reiniciás el pool.
- Validá con tinker:
php artisan tinkery despuésconfig('database.connections.mysql.host')para confirmar que el valor nuevo está.
El punto que más gente se saltea: no corras config:cache hasta que TODO esté en su lugar. Subís el .env, subís el código nuevo, corrés migraciones si hay, y recién ahí cacheás. Si cacheás en el medio, capturás un estado intermedio y roto. Lo explicamos a fondo en prácticas DevOps para deployment seguro.
Shared hosting sin acceso SSH: cómo actualizar .env y limpiar caché
Si no tenés SSH no podés correr comandos Artisan, así que la jugada es forzar la recarga borrando el snapshot a mano. Entrás por FTP o por el administrador de archivos del panel, vas a bootstrap/cache/ y borrás config.php. Sin ese archivo, Laravel vuelve a leer el .env en cada request (más lento, pero funciona). Es la salida más rápida cuando el hosting compartido no te da terminal.
Las opciones ordenadas de menos a más riesgo:
- Borrar
bootstrap/cache/config.phppor FTP: la más limpia. Laravel deja de usar el caché y lee el.envdirecto. También podés borrarroutes-*.phpdel mismo directorio si cacheaste rutas. - Usar la integración del panel: algunos paneles de hosting traen un botón para correr comandos Artisan o limpiar caché de Laravel. Si tu proveedor lo tiene, es lo más prolijo.
- Contactar a soporte: pedile al soporte del hosting que corra
php artisan config:clearpor vos. Tardan, pero es seguro. - Script PHP temporal (riesgoso): subir un
.phpapublic/que llame a Artisan. Funciona, pero si te olvidás de borrarlo dejás un agujero de seguridad enorme. Si lo hacés, borralo apenas termina.
Un consejo aparte: para apps Laravel serias, un hosting con acceso SSH te ahorra todo este baile. Si estás buscando alojamiento en Argentina con soporte para PHP moderno y terminal, mirá las opciones de donweb.com, que te deja correr los comandos Artisan sin depender de un ticket.
Errores comunes que mantienen cacheado tu .env viejo
La mayoría de los casos de “no me toma el cambio” son uno de estos cinco. Ninguno es un bug de Laravel, son descuidos de deployment que le pasan a todo el mundo.
- Editar el
.envsin regenerar el caché: el clásico. El snapshot viejo sigue ahí. Corréconfig:cache(o borrá el archivo si estás sin SSH). - Usar
env()en jobs y listeners: devuelvenullcon caché activo. Mové el valor aconfig/y usáconfig(). - Olvidarse de los queue workers: un worker cachea la config al arrancar y la mantiene en memoria. Aunque regeneres el caché, el worker viejo sigue con los valores anteriores hasta que corrés
php artisan queue:restart. - No reiniciar PHP-FPM: con OPcache activo, a veces el snapshot recién compilado no se toma hasta reiniciar el pool.
- Confundir
cache:clearconconfig:clear:cache:clearvacía el caché de aplicación (la carpetastorage/framework/cache), no toca la config. El que borra el snapshot de configuración esconfig:clear. Confundirlos hace que corras el comando equivocado y sigas viendo el valor viejo.
Debugging: cómo verificar si Laravel usa caché o .env directo
Para saber si estás sirviendo desde el snapshot o desde el .env, chequeá primero si existe bootstrap/cache/config.php. Si el archivo está, Laravel usa el caché y tu .env se ignora. Si no está, lee el .env en vivo. Con eso solo ya sabés en qué modo corrés.
Los métodos que sirven, del más directo al más manual:
- Verificá el archivo:
ls -la bootstrap/cache/config.phppor CLI (o mirá el directorio por FTP). Existe = caché activo. - Comparación en tinker: abrí
php artisan tinkery corréconfig('database.connections.mysql.host')junto aenv('DB_HOST'). Siconfig()te da el valor yenv()te danull, tenés el caché activo (y confirmás por qué tu código debe usarconfig()). - Grep en el snapshot: buscá tu valor dentro de
bootstrap/cache/config.php. Si figura el viejo, ya sabés que hay que regenerar. - Los logs: una conexión fallida a la base vieja en
storage/logs/laravel.logte confirma qué host está usando de verdad.
Dato: phpinfo() a veces se cita como forma de ver si PHP accede al .env, pero no es confiable para esto. Muestra variables de entorno del sistema, no las que Laravel parsea del archivo. Tomalo con pinzas. Ya lo cubrimos antes en evitar problemas de caché y DNS.
Tabla: config:cache vs config:clear vs cache:clear
| Comando | Qué hace | Cuándo usarlo |
|---|---|---|
config:cache | Compila toda la config en bootstrap/cache/config.php | En producción, DESPUÉS de actualizar el .env |
config:clear | Borra bootstrap/cache/config.php | Para que Laravel vuelva a leer el .env en vivo |
cache:clear | Vacía el caché de aplicación (storage/framework/cache) | Para limpiar datos cacheados de la app, NO la config |
route:cache | Compila las rutas en un archivo estático | Junto a config:cache en deployments de producción |
queue:restart | Reinicia los workers de cola | Después de cualquier cambio de config con colas corriendo |

Preguntas Frecuentes
¿Por qué mi archivo .env no se actualiza en el servidor de producción?
Porque existe el archivo bootstrap/cache/config.php y Laravel usa ese snapshot en vez de leer el .env. Mientras el caché de configuración esté activo, editar el .env no tiene efecto. Tenés que correr php artisan config:cache para regenerarlo, o config:clear para eliminarlo y volver a leer el .env directo.
¿Qué comandos artisan debo correr después de cambiar .env?
Corré php artisan config:cache siempre después de subir el .env nuevo, nunca antes. Si usás rutas cacheadas, agregá php artisan route:cache. Con colas corriendo, sumá php artisan queue:restart para que los workers tomen la config actualizada. El comando php artisan optimize hace config, rutas y vistas de una sola vez.
¿Cuál es la diferencia entre config:cache y config:clear en Laravel?
config:cache compila toda la configuración en un archivo estático (bootstrap/cache/config.php) para acelerar los requests en producción. config:clear borra ese archivo para que Laravel vuelva a leer el .env en cada request. Usás el primero en producción y el segundo cuando querés que los cambios del .env se reflejen sin recompilar.
¿Cómo manejar variables de entorno en shared hosting sin acceso CLI?
Sin CLI, borrá bootstrap/cache/config.php por FTP o por el administrador de archivos del panel: Laravel deja de usar el caché y lee el .env en vivo. Otra opción es usar la integración Laravel del panel de hosting si la tiene, o pedirle a soporte que corra php artisan config:clear. Evitá scripts PHP temporales en public/ por el riesgo de seguridad.
¿Por qué env() retorna null en producción si está en el .env?
Porque con el caché de configuración activo, env() deja de leer el archivo .env y devuelve null fuera de los archivos de config/. La documentación de Laravel recomienda llamar a env() solo en archivos de configuración. En controladores, jobs o services usá config('clave'), que sí lee del snapshot compilado y funciona en producción.
Conclusión
El “problema” del .env que no se actualiza casi nunca es un problema: es Laravel haciendo lo que le pediste, servir un snapshot cacheado. La solución de fondo tiene dos patas. Primero, disciplina de deployment: subí el .env, y recién después corré config:cache, en ese orden. Segundo, higiene de código: usá config() en toda tu app y reservá env() para los archivos de config/.
Si estás en hosting compartido sin SSH, la salida rápida es borrar bootstrap/cache/config.php a mano. Y si tu app Laravel ya creció, un hosting con terminal te va a ahorrar cada uno de estos dolores de cabeza. Guardate la tabla de comandos: la próxima vez que un valor no se refleje, en 30 segundos sabés cuál correr.






