Funciona na minha máquina: o mistério do env() que some em produção
"Mas aqui na minha máquina roda perfeitamente" Você terminou a feature. Testou local, passou. Subiu pra produção. E aí, do nada, algo que dependia de uma variável de ambiente simplesmente… parou de funcionar. Sua inte
"Mas aqui na minha máquina roda perfeitamente"
Você terminou a feature. Testou local, passou. Subiu pra produção.
E aí, do nada, algo que dependia de uma variável de ambiente simplesmente… parou de funcionar. Sua integração com o gateway de pagamento agora usa uma chave vazia. O client de uma API externa aponta pra lugar nenhum.
Você abre o log, confere o .env, a variável tá lá, certinha. Roda local de novo: funciona. Em produção: null. 🙃
Se você já viveu essa cena de terror, provavelmente o culpado é um só: você usou env() num lugar que não devia.
O código que parece inofensivo
Digamos que você criou um service pra falar com uma API de frete. Precisa da chave, então você faz o óbvio:
class FreteService
{
public function __construct()
{
// parece certo, né? peguei do .env e pronto
$this->apiKey = env('FRETE_API_KEY');
$this->baseUrl = env('FRETE_API_URL', 'https://api.frete.com');
}
}
Local, isso funciona lindamente. O Laravel lê o .env, encontra FRETE_API_KEY, e a vida segue.
O problema é que esse código carrega uma bomba-relógio. E o pino é puxado por um comando que todo deploy sério roda.
O que o config:cache faz (e por que ele te trai)
Ler o arquivo .env do disco e parsear tudo a cada request é lento. Por isso, em produção, a recomendação oficial é rodar:
php artisan config:cache
Esse comando junta todos os seus arquivos de config/ num único arquivo PHP otimizado e cacheado. A partir daí, o Laravel nunca mais lê o .env — ele lê o cache.
E aqui tá a pegadinha: quando o config está cacheado, a função env() passa a retornar null pra tudo que não estava dentro dos arquivos de config.
Ou seja, aquele env('FRETE_API_KEY') lá no seu service vira null em produção. Local você provavelmente nunca rodou config:cache, por isso "funciona na sua máquina". O bug estava dormindo o tempo todo.
A regra de ouro
env() só deve ser chamado dentro dos arquivos da pasta config/. Nunca em services, controllers, models, jobs ou qualquer outro lugar.
O jeito certo é: você lê o env() no config, e no resto da aplicação você lê o config com config().
Primeiro, cria (ou usa) um arquivo de config:
// config/frete.php
return [
'api_key' => env('FRETE_API_KEY'),
'base_url' => env('FRETE_API_URL', 'https://api.frete.com'),
];
Depois, no service, você troca env() por config():
class FreteService
{
public function __construct()
{
// agora lê do config — que sobrevive ao cache
$this->apiKey = config('frete.api_key');
$this->baseUrl = config('frete.base_url');
}
}
Pronto. Agora o env() mora onde deve, o config:cache empacota o valor junto, e produção passa a se comportar igual ao seu local.
Como usar na prática
O padrão é sempre o mesmo, em qualquer contexto:
-
Chave de API num service → cria uma entrada em
config/services.phpe lê comconfig('services.frete.key'). Aliás, oconfig/services.phpjá existe justamente pra isso. -
Feature flag num controller →
config('app.features.novo_checkout')em vez deenv('NOVO_CHECKOUT'). -
Timeout de um job → coloca em
config/queue.phpou num config seu e chamaconfig('...')lá dentro.
Regra mental simples: se você tá prestes a escrever env() e o arquivo não está dentro de config/, para. Tá quase virando bug de produção.
A pegadinha da pegadinha
"Mas eu uso env() fora do config e funciona!" — sim, funciona enquanto você não rodar config:cache.
O perigo é justamente esse: em desenvolvimento tudo passa, os testes passam, o PR é aprovado. O bug só nasce no primeiro deploy que roda o cache. E aí você vai debugar em produção, no pior momento possível.
Quer testar se seu código tá limpo agora? Roda isso local:
php artisan config:cache
Se algo quebrar depois disso, achou seus env() mal colocados. Pra voltar ao normal no dev:
php artisan config:clear
Bônus: e agora?
Passa um grep no seu projeto atrás de env( fora da pasta config/. Aposto que tem pelo menos um escondido por aí — geralmente num service antigo que "sempre funcionou".
Enquanto tá nisso, dá uma olhada no config/services.php. Ele foi feito pra guardar credenciais de serviços de terceiros, e muita gente ignora que ele existe.
Antes de você fechar a aba
O env() fora do config é aquele bug educado: ele espera você virar as costas pra produção pra dar as caras.
Já perdeu uma tarde caçando um valor que sumia em produção? Conta aí nos comentários qual foi o seu — quero saber se fui só eu. 👀
Se esse tipo de armadilha de Laravel te ajuda, salva o post e me segue: tem mais dessas por aqui.
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.