|

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.php y Laravel usa ese snapshot en vez de tu .env actualizado.
  • El fix normal: corré php artisan config:cache DESPUÉS de subir el .env nuevo, no antes.
  • La regla de oro: tu código debe usar config('database.host'), nunca env('DB_HOST') directo (devuelve null con el caché activo).
  • Sin SSH: en hosting compartido podés borrar bootstrap/cache/config.php por 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:

  1. Actualizá el .env en el servidor con todos los valores nuevos. Recién cuando esté completo pasás al siguiente paso.
  2. Regenerá la config: php artisan config:cache. Esto borra el snapshot viejo y compila uno nuevo con tus valores actuales.
  3. Si usás rutas cacheadas: php artisan route:cache.
  4. Opcional, todo junto: php artisan optimize corre 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 .env primero: asegurate de que todos los cambios estén en el servidor antes de tocar ningún comando de caché.
  • Chequeá permisos: el .env tiene que ser legible por el usuario de PHP, pero nunca world-writable. Un chmod 640 alcanza en la mayoría de los setups.
  • Corré los comandos en orden: config:cache y después route: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 tinker y después config('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.php por FTP: la más limpia. Laravel deja de usar el caché y lee el .env directo. También podés borrar routes-*.php del 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:clear por vos. Tardan, pero es seguro.
  • Script PHP temporal (riesgoso): subir un .php a public/ 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 .env sin 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: devuelve null con caché activo. Mové el valor a config/ 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:clear con config:clear: cache:clear vacía el caché de aplicación (la carpeta storage/framework/cache), no toca la config. El que borra el snapshot de configuración es config: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.php por CLI (o mirá el directorio por FTP). Existe = caché activo.
  • Comparación en tinker: abrí php artisan tinker y corré config('database.connections.mysql.host') junto a env('DB_HOST'). Si config() te da el valor y env() te da null, tenés el caché activo (y confirmás por qué tu código debe usar config()).
  • 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.log te 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

ComandoQué haceCuándo usarlo
config:cacheCompila toda la config en bootstrap/cache/config.phpEn producción, DESPUÉS de actualizar el .env
config:clearBorra bootstrap/cache/config.phpPara que Laravel vuelva a leer el .env en vivo
cache:clearVacía el caché de aplicación (storage/framework/cache)Para limpiar datos cacheados de la app, NO la config
route:cacheCompila las rutas en un archivo estáticoJunto a config:cache en deployments de producción
queue:restartReinicia los workers de colaDespués de cualquier cambio de config con colas corriendo
hosting laravel env changes diagrama explicativo

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.

Fuentes

Te puede interesar...