Dev.to WebDev 🛠 Dev 👁 1 📖 4 min read

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.php e lê com config('services.frete.key'). Aliás, o config/services.php já existe justamente pra isso.
  • Feature flag num controller → config('app.features.novo_checkout') em vez de env('NOVO_CHECKOUT').
  • Timeout de um job → coloca em config/queue.php ou num config seu e chama config('...') 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.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.