Tips & Tricks (Mis à jour: 02/06/2026)

Variables d'environnement avec Claude Code : .env, Zod, Secrets et déploiement

Gérez les variables d'environnement et Secrets avec Claude Code : .env.example, Zod, CI/CD, redaction et rotation.

Variables d'environnement avec Claude Code : .env, Zod, Secrets et déploiement

Quand on demande à Claude Code de créer une authentification, un paiement, un webhook ou une intégration IA, le premier vrai problème de production n’est pas toujours le composant UI. Il vient souvent de la configuration : une URL de base de données manquante, une clé de staging utilisée en production, un WEBHOOK_SECRET imprimé dans les logs CI, ou une vraie API key poussée sur GitHub.

Ce guide propose un modèle prêt à implémenter pour gérer les variables d’environnement et les Secrets avec Claude Code. Une variable d’environnement est une valeur donnée à l’application au démarrage, comme PORT ou APP_ORIGIN. Un Secret est une valeur exploitable si elle fuit, comme ANTHROPIC_API_KEY, DATABASE_URL ou WEBHOOK_SECRET. Un Secret peut être transmis via une variable d’environnement, mais il ne doit pas être traité comme une simple option.

Pour la configuration propre à Claude Code, consultez la référence officielle Claude Code environment variables. Pour valider la configuration applicative, nous utiliserons Zod. Côté CI/CD et déploiement, les références utiles sont GitHub Actions secrets, Vercel environment variables, Cloudflare Workers variables and secrets et Docker secrets. Les interfaces changent selon la plateforme, mais le principe reste le même : versionnez les noms et les règles, jamais les valeurs secrètes.

Pour compléter la posture de sécurité, lisez aussi les bonnes pratiques de sécurité Claude Code et l’authentification JWT avec Claude Code.

Considérez .env comme un contrat

Un fichier .env est pratique, mais il ne doit pas devenir le carnet privé de chaque développeur. Une équipe a besoin de trois couches :

  • Déclaration : .env.example liste les clés nécessaires
  • Validation : Zod bloque le démarrage si une valeur manque ou n’a pas le bon format
  • Opérations : CI/CD et production injectent les valeurs depuis les Secrets de la plateforme
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

Le point important : toutes les entrées passent par le même schema. Claude Code doit recevoir les noms de clés, les règles de validation et le comportement en cas d’erreur, pas les vraies valeurs de production.

Cas d’usage concrets

CasVariables typiquesRisque si cela échoue
Développement localAPP_ORIGIN, DATABASE_URL, ANTHROPIC_API_KEYL’app ne fonctionne que sur une machine
Vérification de webhookSTRIPE_WEBHOOK_SECRET, WEBHOOK_SECRETDes requêtes falsifiées sont acceptées
Tests CICI_DATABASE_URL, TEST_API_KEYLa PR passe mais le déploiement échoue
ProductionDATABASE_URL, SESSION_SECRET, APP_ORIGINMauvaise base, cookies invalides, fuite de credentials
Rotation de secretsANTHROPIC_API_KEY_NEXTUne ancienne clé compromise reste valide

Dans le workflow ClaudeCodeLab de Masa, le plus grand gain n’a pas été seulement de créer .env.example, mais de faire refuser le démarrage quand le contrat est incomplet. Les surprises de déploiement deviennent alors des erreurs visibles en pull request.

1. Séparez les fichiers

.env.example documente le projet, sans valeurs réelles. .env.local est propre à une machine. .env.production.example est une checklist de production, sans 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

Les placeholders ne sont pas des valeurs par défaut sûres. Ils indiquent simplement qu’une valeur doit être fournie ailleurs.

2. Validez avec Zod au démarrage

Dans Node.js, les variables d’environnement arrivent sous forme de chaînes. Même PORT=3000 est une chaîne ; z.coerce.number() la convertit et vérifie la plage.

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 ?? "",
  };
}

Vérifiez localement :

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

Demandez ensuite à Claude Code de centraliser les accès :

Trouve toutes les lectures directes de process.env dans ce dépôt.
Seul src/config/env.ts doit lire process.env directement.
Pour les autres fichiers, propose d'importer env depuis src/config/env.ts.
N'imprime aucun secret dans les logs, erreurs ou snapshots de test.

3. Masquez avant de logger

Les fuites ne viennent pas seulement de Git. Elles apparaissent dans les logs CI, les sorties de debug, l’error tracking, les captures d’écran ou les prompts collés dans 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));

Le masquage est une dernière protection. Le meilleur log est celui qui ne reçoit jamais le secret.

4. Injectez via CI/CD

GitHub Actions peut injecter des secrets de dépôt, d’environnement ou d’organisation. N’utilisez pas les credentials de production pour les tests de pull request ; créez des valeurs CI limitées.

# .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

Tous les workflows ne reçoivent pas les secrets de la même manière. Les PR depuis forks, les workflows réutilisables ou certains événements automatisés ont des limites. Gardez le job de validation explicite et n’écrivez pas les secrets dans des fichiers générés.

5. Docker, Vercel, Cloudflare

Dans Docker, n’inscrivez pas ENV API_KEY=... dans le Dockerfile. Pour un test local, un env file suffit ; en production, utilisez le secret store ou l’orchestrateur.

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

Si votre runtime expose des secrets sous forme de fichiers, supportez la convention 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();
}

Sur Vercel, séparez Production, Preview et Development. Faites attention aux préfixes exposés au navigateur comme NEXT_PUBLIC_. Sur Cloudflare Workers, les valeurs arrivent via bindings, paramètre env ou Secrets de plateforme. Ne promettez pas une portabilité magique : documentez l’injection par plateforme et gardez le schema comme source de vérité.

Passe en revue la configuration d'environnement pour Vercel, Cloudflare et Docker.
Ne lis pas et ne demande pas les vraies valeurs de production.
Vérifie les clés obligatoires, public vs secret, build-time vs runtime, et les notes de rotation.

6. Rédigez un playbook de rotation

La rotation des Secrets ne doit pas être improvisée pendant un incident :

  1. Identifier le périmètre : service, environnement, permissions, responsable
  2. Créer une nouvelle valeur avec permissions minimales
  3. L’ajouter en *_NEXT si une double acceptation est possible
  4. Déployer une compatibilité temporaire avec l’ancienne et la nouvelle valeur
  5. Basculer et vérifier les health checks
  6. Révoquer l’ancienne valeur
  7. Chercher l’exposition dans Git, CI, logs et prompts
  8. Mettre à jour .env.example et les notes d’exploitation

Un webhook secret, une API key et un mot de passe de base ne se remplacent pas de la même façon. Documentez le propriétaire, la fenêtre et le rollback pour chaque type.

Échecs fréquents

ÉchecCauseCorrection
.env committé.gitignore ajouté trop tardRévoquer les clés ; nettoyer Git ne suffit pas
Secret dans NEXT_PUBLIC_Préfixe public mal comprisSéparer conventions public/private
console.log(process.env)Debug urgentRedaction et revue des logs
Production ne démarre pasClé obligatoire absenteExécuter src/config/env.ts en CI
Valeur locale dans build prodConfusion build-time/runtimeDocumenter l’injection par plateforme
Vraie clé collée dans Claude CodePrompt confondu avec partage secretPartager noms et règles, pas les valeurs

Prompt prêt pour Claude Code

Implémente la gestion des variables d'environnement pour ce projet.

Exigences :
- Créer .env.example et .env.production.example
- Garder .env, .env.* et .dev.vars* hors de Git
- Ajouter un schema Zod dans src/config/env.ts et échouer au démarrage si une valeur manque
- Centraliser les lectures directes de process.env dans src/config/env.ts
- Masquer les secrets dans les logs de diagnostic
- Ajouter un job GitHub Actions qui valide l'environnement sur les pull requests
- Ajouter de courtes notes de déploiement pour Vercel, Cloudflare et Docker

Ne lis pas de vraies API keys ni d'URL de base de production. Travaille seulement avec les noms de clés et règles de validation.

Conclusion

Bien utiliser Claude Code pour la configuration ne consiste pas à coller des secrets dans le chat. Il faut lui faire implémenter un contrat : .env.example déclare les clés, Zod valide au démarrage, les logs sont masqués, CI/CD et la plateforme injectent les vraies valeurs, et l’équipe sait faire une rotation.

ClaudeCodeLab propose du conseil Claude Code, de la formation d’équipe, des revues de sécurité de dépôts et des templates pour l’authentification, les paiements, le CI/CD et les opérations de contenu. Si votre équipe veut accélérer sans exposer les clés de production, cette fondation est l’une des premières à standardiser.

Dans le dépôt de test de Masa, ce modèle a détecté avant déploiement une clé production manquante, un webhook secret susceptible d’apparaître dans les logs et un .env.example obsolète. La validation Zod au démarrage est simple, mais elle transforme la configuration en contrat vérifiable.

#Claude Code #variables d'environnement #Secrets #Zod #CI/CD #TypeScript
Gratuit

PDF gratuit: cheatsheet Claude Code

Saisissez votre email et téléchargez une page avec commandes, habitudes de review et workflow sûr.

Nous protégeons vos données et n'envoyons pas de spam.

Masa

À propos de l'auteur

Masa

Ingénieur spécialisé dans les workflows pratiques avec Claude Code.