Variáveis de ambiente não chegam ao contêiner
Quando as variáveis de ambiente não funcionam em um contêiner, geralmente há um de cinco motivos: build versus runtime, bundling do frontend, aspas, momento da reinicialização ou escopo incorreto. Verifique-os nesta ordem.
Você definiu a variável. O dashboard a mostra. A aplicação diz que ela é undefined. Variáveis de ambiente não funcionarem em um contêiner é uma das falhas de configuração mais comuns em hospedagem de aplicações e quase sempre se deve a um de cinco motivos específicos.
Eles estão listados na ordem que permite encontrar o problema mais rapidamente.
1. Build e runtime são mundos diferentes
Esse motivo causa mais casos do que os outros quatro juntos e é o menos intuitivo para a maioria das pessoas.
As variáveis definidas no serviço existem quando o contêiner é executado. Tudo o que o Dockerfile faz acontece antes, em um ambiente separado. Um passo RUN não consegue acessar uma variável de runtime, porque, naquele momento, ainda não existe um runtime.
# This is empty during build. Always.
RUN echo $DATABASE_URL
# This is available at runtime, because it is the running process reading it
CMD ["node", "server.js"]
Se você realmente precisa de um valor durante o build, ele precisa ser passado como um build argument — que é um mecanismo diferente, com propriedades de segurança diferentes:
ARG BUILD_VERSION
RUN echo "Building $BUILD_VERSION"
Nunca passe um segredo dessa forma. Os build arguments ficam registrados no histórico de camadas da imagem. Qualquer pessoa que consiga fazer pull da imagem pode lê-los.
2. As variáveis do frontend são incorporadas ao bundle, não lidas
Se o frontend informa undefined em produção, este é quase certamente o motivo.
Um navegador não tem ambiente. Quando você escreve import.meta.env.VITE_API_URL ou process.env.NEXT_PUBLIC_API_URL, o bundler substitui o valor pelo texto literal durante o build. Não há nenhuma consulta acontecendo no navegador — o valor foi compilado no bundle.
Três consequências costumam causar problemas:
- Alterar a variável não faz nada até que você faça um novo build. O valor antigo está dentro do arquivo JavaScript.
- O prefixo é obrigatório. O Vite só expõe variáveis
VITE_, e o Next.js só expõe variáveisNEXT_PUBLIC_. Uma variável sem o prefixo é deliberadamente ocultada. - Tudo o que é exposto dessa forma é público. O valor fica em um arquivo que você disponibiliza para qualquer pessoa. Nunca coloque um segredo atrás de
NEXT_PUBLIC_, independentemente do que o nome possa sugerir.
É também por isso que uma imagem predefinida não pode ser configurada dessa forma posteriormente. Se a imagem foi criada em outro lugar com os valores compilados, definir variáveis no serviço não muda nada — as strings já estão no bundle.
3. Aspas
Valores com caracteres especiais podem ser alterados de maneiras que produzem erros confusos, em vez de erros óbvios.
# The shell eats everything after #
dockup env set DB_PASS=p@ss#word my-project/my-api
# Quote it
dockup env set 'DB_PASS=p@ss#word' my-project/my-api
Os caracteres que causam esse problema são: # (comentário), $ (expansão), espaços (separação de argumentos), ! (expansão do histórico em um bash interativo) e quebras de linha — que aparecem em um caso comum específico: chaves privadas.
Valores com várias linhas são os que mais causam problemas. Quando uma chave PEM é colada em um campo de uma única linha, suas quebras de linha são removidas, gerando um erro de análise que não menciona nada sobre quebras de linha. Codifique o valor em Base64 e faça a decodificação na aplicação:
dockup env set "PRIVATE_KEY_B64=$(base64 -i key.pem)" my-project/my-api
4. Você não reiniciou
As variáveis de ambiente são lidas por um processo quando ele é iniciado. Alterá-las afeta o próximo processo, não o que está em execução no momento.
A maioria das plataformas resolve isso fazendo um novo deploy automaticamente quando a configuração muda, mas nem todas fazem isso. Além disso, uma alteração parcial — definir três variáveis, fazer o deploy e definir uma quarta — deixa uma delas para trás.
dockup env list my-project/my-api --json # what is configured
dockup restart my-project/my-api # make the process re-read it
A verificação definitiva é ler a variável de dentro do contêiner em execução, e não do dashboard.
dockup exec "printenv | sort" my-project/my-api
Se ela aparecer nessa saída e sua aplicação ainda informar que está undefined, o problema está no seu código. Se não aparecer, o problema está na configuração. Esse único comando divide o espaço de busca ao meio.
5. Escopo incorreto
As variáveis geralmente têm escopo — um serviço, um ambiente ou um projeto. Uma variável definida em produção não fica visível em um ambiente de preview. Da mesma forma, uma variável definida em outro serviço do mesmo projeto também não fica visível.
Essa é a causa mais comum quando algo funciona em um lugar, mas não em outro com o mesmo código.
A ordem do diagnóstico
# 1. Is it actually in the container's environment?
dockup exec "printenv | sort" my-project/my-api
# 2. Is it configured on the service you think it is?
dockup env list my-project/my-api --json
# 3. Is the running process older than the change?
dockup status my-project/my-api --json
Comece sempre pelo passo 1. Ele transforma um problema ambíguo em um de dois problemas inequívocos.
Especificamente sobre segredos
Vale a pena adotar dois hábitos, independentemente da plataforma.
Marque os segredos como segredos. No Dockup, uma variável marcada como secreta aparece mascarada nas listagens e nas respostas da API — dockup env list mostra ******** em vez do valor. Isso é mais importante do que pode parecer, porque a forma mais comum de um segredo vazar não é um ataque; é uma captura de tela, um chamado ao suporte ou uma linha de log.
Mantenha-os fora dos build arguments e dos bundles do frontend. Ambos podem ser lidos por qualquer pessoa que obtenha o artefato. A regra geral é: se o valor acaba em um arquivo que você distribui, ele não é mais um segredo.
Perguntas frequentes
Por que minha variável de ambiente está undefined durante o build? Porque build e runtime são ambientes separados. As variáveis de runtime não existem enquanto a imagem está sendo criada. Use um build argument se realmente precisar de um valor durante o build — e nunca use um segredo.
Por que meu frontend não consegue acessar a variável?
Os bundlers substituem o valor durante o build e só expõem nomes com prefixos — VITE_, NEXT_PUBLIC_. Alterar a variável exige um novo build, e tudo o que é exposto dessa forma pode ser lido publicamente.
Preciso reiniciar depois de alterar uma variável?
Sim. Um processo em execução já leu o ambiente. A maioria das plataformas faz um novo deploy automaticamente quando há alterações; confirme usando printenv dentro do contêiner, em vez de confiar no dashboard.
Como passo um valor com várias linhas, como uma chave privada? Codifique-o em Base64, defina a string codificada e faça a decodificação na aplicação. Campos de ambiente de uma única linha removem as quebras de linha e geram erros de análise que não mencionam essas quebras.
