Tips & Tricks (Atualizado: 02/06/2026)

Variáveis de ambiente no Claude Code: .env, Zod, Secrets e deploy seguro

Gerencie variáveis de ambiente e Secrets com Claude Code: .env.example, validação Zod, CI/CD, redação e rotação.

Variáveis de ambiente no Claude Code: .env, Zod, Secrets e deploy seguro

Quando alguém começa a usar Claude Code para criar login, pagamentos, webhooks ou integrações de IA, o primeiro problema sério em produção geralmente não está na interface. Ele aparece na configuração: uma URL de banco ausente, uma chave de staging usada em produção, um WEBHOOK_SECRET impresso em logs de CI ou uma API key real enviada ao GitHub.

Este guia mostra um padrão pronto para implementar gerenciamento de variáveis de ambiente e Secrets com Claude Code. Uma variável de ambiente é um valor entregue à aplicação em tempo de execução, como PORT ou APP_ORIGIN. Um Secret é um valor que pode ser abusado se vazar, como ANTHROPIC_API_KEY, DATABASE_URL ou WEBHOOK_SECRET. Secrets podem chegar por variáveis de ambiente, mas precisam de regras mais rígidas.

Para a configuração do próprio Claude Code, consulte a referência oficial Claude Code environment variables. Para validar a configuração da aplicação, usaremos Zod. Em CI/CD e deploy, use como base GitHub Actions secrets, Vercel environment variables, Cloudflare Workers variables and secrets e Docker secrets. Cada plataforma tem sua interface, mas a regra é a mesma: versionar nomes e regras, nunca valores secretos.

Para reforçar o contexto de segurança, leia também boas práticas de segurança com Claude Code e autenticação JWT com Claude Code.

Trate .env como contrato

Um arquivo .env é útil, mas não deve virar um caderno particular de cada pessoa. A equipe precisa de três camadas:

  • Declaração: .env.example lista as chaves necessárias
  • Validação: Zod falha no boot quando algo está ausente ou inválido
  • Operação: CI/CD e produção injetam valores pelos Secrets da plataforma
flowchart LR
  Dev["local .env.local"] --> Schema["Zod schema"]
  CI["GitHub Actions secrets"] --> Schema
  Prod["Vercel / Cloudflare / Docker secrets"] --> Schema
  Schema --> App["Type-safe app config"]
  Schema --> Logs["Redacted logs"]
  Example[".env.example"] --> Dev

O ponto prático é que todas as entradas passam pelo mesmo schema. Claude Code deve receber nomes de chaves, regras de validação e comportamento de erro, não valores reais de produção.

Casos de uso reais

CasoVariáveis comunsFalha típica
Desenvolvimento localAPP_ORIGIN, DATABASE_URL, ANTHROPIC_API_KEYA app só funciona na máquina de uma pessoa
Verificação de webhooksSTRIPE_WEBHOOK_SECRET, WEBHOOK_SECRETRequisições falsas são aceitas
Testes em CICI_DATABASE_URL, TEST_API_KEYPR passa, mas deploy falha
ProduçãoDATABASE_URL, SESSION_SECRET, APP_ORIGINBanco errado, cookie errado ou credential vazado
Rotação de SecretsANTHROPIC_API_KEY_NEXTUma chave antiga comprometida continua válida

No fluxo de Masa para ClaudeCodeLab, o ganho maior não foi apenas criar .env.example, mas fazer a aplicação se recusar a iniciar quando o contrato está incompleto. Isso transforma surpresas de deploy em falhas revisáveis no PR.

1. Separe os arquivos

.env.example é documentação, não armazenamento de valores reais. .env.local pertence a uma máquina local. .env.production.example é uma checklist de produção sem secrets.

mkdir -p src/config
touch .env.example .env.local .env.production.example src/config/env.ts
# .gitignore
.env
.env.*
!.env.example
!.env.production.example

# Cloudflare local secrets
.dev.vars
.dev.vars.*
# .env.example
APP_ENV=local
NODE_ENV=development
PORT=3000
APP_ORIGIN=http://localhost:3000
DATABASE_URL=postgresql://app:app@localhost:5432/app
ANTHROPIC_API_KEY=replace-with-local-dev-key
WEBHOOK_SECRET=replace-with-32-plus-character-secret
PUBLIC_ANALYTICS_KEY=
LOG_LEVEL=info
# .env.production.example
APP_ENV=production
NODE_ENV=production
PORT=3000
APP_ORIGIN=https://example.com
DATABASE_URL=<set-in-platform-secret-store>
ANTHROPIC_API_KEY=<set-in-platform-secret-store>
WEBHOOK_SECRET=<set-in-platform-secret-store>
PUBLIC_ANALYTICS_KEY=<optional-public-key>
LOG_LEVEL=info

Os placeholders não são defaults seguros. Eles só dizem que um valor precisa ser fornecido em outro lugar.

2. Valide com Zod no boot

Em Node.js, variáveis de ambiente chegam como texto. Mesmo PORT=3000 é string, então usamos z.coerce.number() para converter e validar.

npm install zod dotenv
npm install -D tsx typescript @types/node
// src/config/env.ts
import "dotenv/config";
import { z } from "zod";

const secretNamePattern = /(SECRET|TOKEN|PASSWORD|API_KEY|DATABASE_URL|DSN)/i;

function redactValue(key: string, value: unknown): string {
  if (value === undefined || value === null || value === "") return "<empty>";
  const text = String(value);
  if (!secretNamePattern.test(key)) return text;
  if (text.length <= 8) return "<redacted>";
  return `${text.slice(0, 4)}...${text.slice(-4)}`;
}

const envSchema = z.object({
  APP_ENV: z.enum(["local", "development", "staging", "production"]).default("local"),
  NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
  PORT: z.coerce.number().int().min(1).max(65535).default(3000),
  APP_ORIGIN: z.string().url(),
  DATABASE_URL: z.string().url(),
  ANTHROPIC_API_KEY: z.string().min(20, "ANTHROPIC_API_KEY is too short"),
  WEBHOOK_SECRET: z.string().min(32, "WEBHOOK_SECRET must be at least 32 characters"),
  PUBLIC_ANALYTICS_KEY: z.string().optional(),
  LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
});

const parsed = envSchema.safeParse(process.env);

if (!parsed.success) {
  console.error("Environment validation failed:");
  for (const issue of parsed.error.issues) {
    const key = String(issue.path[0] ?? "unknown");
    console.error(`- ${key}: ${issue.message}; current=${redactValue(key, process.env[key])}`);
  }
  process.exit(1);
}

export const env = Object.freeze(parsed.data);
export type AppEnv = typeof env;

export function isProduction(): boolean {
  return env.APP_ENV === "production";
}

export function publicEnv() {
  return {
    APP_ENV: env.APP_ENV,
    APP_ORIGIN: env.APP_ORIGIN,
    PUBLIC_ANALYTICS_KEY: env.PUBLIC_ANALYTICS_KEY ?? "",
  };
}

Teste localmente:

cp .env.example .env.local
npx tsx src/config/env.ts

Depois peça ao Claude Code para centralizar os acessos:

Encontre todas as leituras diretas de process.env neste repositório.
Somente src/config/env.ts deve ler process.env diretamente.
Nos outros arquivos, proponha importar env de src/config/env.ts.
Não imprima secrets em logs, erros ou snapshots de teste.

3. Redija antes de logar

Vazamentos não acontecem só no Git. Eles aparecem em logs de CI, saída de debug, error tracking, gravações de tela ou prompts colados no Claude Code.

// src/config/redact.ts
const sensitiveKeyPattern = /(SECRET|TOKEN|PASSWORD|API_KEY|DATABASE_URL|AUTH|COOKIE|PRIVATE)/i;

export function redactSecrets(input: Record<string, unknown>): Record<string, string> {
  return Object.fromEntries(
    Object.entries(input).map(([key, value]) => {
      if (value === undefined || value === null || value === "") return [key, "<empty>"];
      const text = String(value);
      if (!sensitiveKeyPattern.test(key)) return [key, text];
      return [key, text.length <= 10 ? "<redacted>" : `${text.slice(0, 4)}...${text.slice(-4)}`];
    }),
  );
}
import { env } from "./env";
import { redactSecrets } from "./redact";

console.info("Loaded config", redactSecrets(env));

Redaction é uma proteção final. O melhor log é aquele que nunca recebe o secret.

4. Injete valores via CI/CD

GitHub Actions permite secrets em nível de repositório, ambiente ou organização. Não reutilize credenciais de produção em testes normais de PR; crie valores de CI com escopo menor.

# .github/workflows/env-check.yml
name: env-check

on:
  pull_request:
  push:
    branches: [main]

jobs:
  validate-env:
    runs-on: ubuntu-latest
    env:
      APP_ENV: development
      NODE_ENV: test
      PORT: 3000
      APP_ORIGIN: http://localhost:3000
      DATABASE_URL: ${{ secrets.CI_DATABASE_URL }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      WEBHOOK_SECRET: ${{ secrets.WEBHOOK_SECRET }}
      LOG_LEVEL: info
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "22"
          cache: npm
      - run: npm ci
      - name: Mask runtime-only values
        run: echo "::add-mask::$APP_ORIGIN"
      - run: npx tsx src/config/env.ts
      - run: npm test -- --runInBand

Nem todo workflow recebe secrets nas mesmas condições. Fork PRs, reusable workflows e eventos automatizados podem ter restrições. Mantenha o job de validação explícito e não escreva secrets em arquivos gerados.

5. Docker, Vercel e Cloudflare

No Docker, não coloque ENV API_KEY=... no Dockerfile. Para teste local, um env file é aceitável; em produção, prefira o mecanismo de secrets do runtime.

# local only
docker run --rm --env-file .env.local my-app:latest

Se o runtime expõe secrets como arquivos, suporte a convenção NAME_FILE:

// src/config/secret-file.ts
import fs from "node:fs";

export function readEnvOrFile(name: string): string | undefined {
  const direct = process.env[name];
  if (direct) return direct;

  const filePath = process.env[`${name}_FILE`];
  if (!filePath) return undefined;
  return fs.readFileSync(filePath, "utf8").trim();
}

Na Vercel, separe Production, Preview e Development. Tenha cuidado com prefixos visíveis no navegador, como NEXT_PUBLIC_. No Cloudflare Workers, valores chegam por bindings, pelo parâmetro env ou por Secrets da plataforma. Não prometa portabilidade automática: documente o ponto de injeção por plataforma e deixe o schema como fonte da verdade.

Revise a configuração de ambiente para Vercel, Cloudflare e Docker.
Não leia nem peça valores reais de produção.
Verifique chaves obrigatórias, public vs secret, build-time vs runtime e notas de rotação.

6. Escreva um playbook de rotação

Rotação de Secrets não deve ser improvisada durante um incidente:

  1. Identifique escopo: serviço, ambiente, permissões e responsável
  2. Crie o novo valor com permissões mínimas
  3. Adicione como *_NEXT quando for possível aceitar dois valores
  4. Faça deploy aceitando valor antigo e novo por uma janela curta
  5. Troque o tráfego e verifique health checks
  6. Revogue o valor antigo
  7. Procure exposição em Git, CI, logs e prompts
  8. Atualize .env.example e notas operacionais

Webhook secret, API key e senha de banco têm mecânicas diferentes. Documente dono, janela e rollback para cada tipo.

Falhas comuns

FalhaCausaCorreção
.env commitado.gitignore veio tardeRevogue chaves; limpar histórico não basta
Secret em NEXT_PUBLIC_Prefixo público mal entendidoSepare convenções public/private
console.log(process.env)Debug apressadoUse redaction e revisão de logs
Produção não iniciaChave obrigatória ausenteRode src/config/env.ts no CI
Valor local no build de produçãoConfusão build-time/runtimeDocumente injeção por plataforma
Chave real colada no Claude CodePrompt confundido com compartilhamento de secretEnvie nomes e regras, não valores

Prompt pronto para Claude Code

Implemente gerenciamento de variáveis de ambiente para este projeto.

Requisitos:
- Criar .env.example e .env.production.example
- Manter .env, .env.* e .dev.vars* fora do Git
- Adicionar schema Zod em src/config/env.ts e falhar no boot se houver valor ausente ou inválido
- Centralizar leituras diretas de process.env em src/config/env.ts
- Redigir secrets em logs de diagnóstico
- Adicionar job GitHub Actions que valida env em pull requests
- Escrever notas curtas de deploy para Vercel, Cloudflare e Docker

Não leia API keys reais nem URLs de banco de produção. Trabalhe apenas com nomes de chaves e regras de validação.

Conclusão

Usar Claude Code para gestão de ambiente não significa colar secrets no chat. Significa implementar um contrato: .env.example declara as chaves, Zod valida no boot, logs são redigidos, CI/CD e a plataforma injetam valores reais, e a equipe tem um playbook de rotação.

ClaudeCodeLab oferece consultoria Claude Code, treinamento de equipes, revisão de segurança de repositórios e templates para autenticação, pagamentos, CI/CD e operações de conteúdo. Se sua equipe quer acelerar sem vazar chaves de produção, esta base deve ser uma das primeiras a padronizar.

No repositório de teste de Masa, esse padrão encontrou antes do deploy uma chave de produção ausente, um Webhook secret que poderia aparecer em logs e um .env.example desatualizado. A validação de boot com Zod é simples, mas transforma configuração em contrato verificável.

#Claude Code #variáveis de ambiente #Secrets #Zod #CI/CD #TypeScript
Grátis

PDF grátis: cheatsheet do Claude Code

Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.

Cuidamos dos seus dados e não enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.