Tips & Tricks (Aktualisiert: 2.6.2026)

Claude Code Environment Management: .env, Zod, Secrets und sichere Deployments

Umgebungsvariablen und Secrets mit Claude Code verwalten: .env.example, Zod-Validierung, CI/CD, Redaction und Rotation.

Claude Code Environment Management: .env, Zod, Secrets und sichere Deployments

Wenn Einsteiger Claude Code bitten, Login, Payments, Webhooks oder eine KI-Integration zu bauen, liegt der erste ernste Produktionsfehler oft nicht im UI. Er liegt in der Konfiguration: eine fehlende Datenbank-URL, ein Staging-Key in Production, ein WEBHOOK_SECRET in CI-Logs oder ein echter API-Key in GitHub.

Dieser Leitfaden zeigt ein direkt nutzbares Muster für Umgebungsvariablen und Secrets mit Claude Code. Eine Umgebungsvariable ist ein Wert, der der App zur Laufzeit übergeben wird, zum Beispiel PORT oder APP_ORIGIN. Ein Secret ist ein Wert, der bei Offenlegung missbraucht werden kann, etwa ANTHROPIC_API_KEY, DATABASE_URL oder WEBHOOK_SECRET. Secrets können technisch als Umgebungsvariablen ankommen, brauchen aber strengere Regeln.

Für Claude Codes eigene Konfiguration ist die offizielle Referenz Claude Code environment variables maßgeblich. Für die App-Validierung nutzen wir Zod. Für CI/CD und Deployments sind GitHub Actions secrets, Vercel environment variables, Cloudflare Workers variables and secrets und Docker secrets die relevanten offiziellen Quellen. Die Plattformen unterscheiden sich, aber das Prinzip bleibt gleich: Namen und Regeln versionieren, nie die Secret-Werte.

Für die breitere Sicherheitsbasis passen dazu Claude Code Security Best Practices und JWT-Authentifizierung mit Claude Code.

.env als Vertrag behandeln

Eine .env-Datei ist praktisch, darf aber nicht zum privaten Notizblock jedes Entwicklers werden. Ein Team braucht drei Schichten:

  • Deklaration: .env.example listet die benötigten Keys
  • Validierung: Zod bricht beim Start ab, wenn Werte fehlen oder ungültig sind
  • Betrieb: CI/CD und Production injizieren Werte aus Plattform-Secrets
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

Der Kern: Alle Eingänge laufen durch dasselbe Schema. Claude Code bekommt Key-Namen, Validierungsregeln und Fehlerverhalten, aber keine echten Produktionswerte.

Konkrete Einsatzfälle

EinsatzfallTypische VariablenFehlerbild
Lokale EntwicklungAPP_ORIGIN, DATABASE_URL, ANTHROPIC_API_KEYDie App läuft nur auf einem Rechner
Webhook-PrüfungSTRIPE_WEBHOOK_SECRET, WEBHOOK_SECRETGefälschte Requests werden akzeptiert
CI-TestsCI_DATABASE_URL, TEST_API_KEYPR grün, Deployment rot
ProductionDATABASE_URL, SESSION_SECRET, APP_ORIGINFalsche DB, Cookie-Probleme, Credential-Leak
Secret-RotationANTHROPIC_API_KEY_NEXTEin kompromittierter alter Key bleibt gültig

In Masas ClaudeCodeLab-Workflow war der größte Hebel nicht nur eine .env.example, sondern ein Startabbruch bei unvollständiger Konfiguration. So werden Deployment-Überraschungen zu überprüfbaren PR-Fehlern.

1. Dateien sauber trennen

.env.example ist Dokumentation, keine Ablage für echte Werte. .env.local gehört zu einer Maschine. .env.production.example ist eine Production-Checkliste ohne 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

Die Platzhalter sind keine sicheren Defaults. Sie markieren nur, dass an anderer Stelle ein Wert gesetzt werden muss.

2. Beim Start mit Zod validieren

In Node.js sind Umgebungsvariablen zunächst Strings. Auch PORT=3000 ist ein String, deshalb konvertiert und prüft z.coerce.number() den Wert.

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

Lokal prüfen:

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

Danach kann Claude Code verstreute Zugriffe finden:

Finde alle direkten process.env-Zugriffe in diesem Repository.
Nur src/config/env.ts soll process.env direkt lesen.
Für andere Dateien schlage vor, env aus src/config/env.ts zu importieren.
Secrets dürfen nicht in Logs, Fehlern oder Test-Snapshots erscheinen.

3. Vor dem Logging redigieren

Secret-Leaks entstehen nicht nur durch Git. Sie tauchen in CI-Logs, Debug-Ausgaben, Error-Tracking, Bildschirmaufnahmen oder in Claude-Code-Prompts auf.

// 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 ist die letzte Sicherung. Noch besser ist ein Log, das den Secret-Wert nie erhält.

4. Werte über CI/CD injizieren

GitHub Actions kann Secrets auf Repository-, Environment- oder Organization-Ebene übergeben. Verwenden Sie für normale PR-Tests keine Production-Credentials, sondern eingeschränkte CI-Werte.

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

Nicht jeder Workflow erhält Secrets unter denselben Bedingungen. Fork-PRs, wiederverwendbare Workflows und automatisierte Events können eingeschränkt sein. Halten Sie die Validierung explizit und schreiben Sie Secrets nicht in generierte Dateien.

5. Docker, Vercel und Cloudflare

In Docker sollten echte Secrets nicht mit ENV API_KEY=... im Dockerfile landen. Lokal ist ein env file in Ordnung; in Production sollte die Runtime oder der Secret Store injizieren.

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

Wenn die Runtime Secrets als Dateien bereitstellt, unterstützt die NAME_FILE-Konvention:

// 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();
}

Auf Vercel trennen Sie Production, Preview und Development. Achten Sie besonders auf im Browser sichtbare Präfixe wie NEXT_PUBLIC_. In Cloudflare Workers kommen Werte je nach Setup über Bindings, den env-Parameter oder Plattform-Secrets. Nicht auf magische Portabilität vertrauen: Schema als Quelle der Wahrheit halten und die Injektionsstelle je Plattform dokumentieren.

Prüfe die Environment-Konfiguration für Vercel, Cloudflare und Docker.
Lies oder fordere keine echten Production-Werte an.
Prüfe Pflicht-Keys, public vs secret, build-time vs runtime und fehlende Rotationsnotizen.

6. Rotations-Playbook vorher schreiben

Secret-Rotation darf nicht erst im Incident entstehen:

  1. Scope klären: Service, Umgebung, Berechtigungen, Owner
  2. Neuen Wert mit minimalen Berechtigungen erstellen
  3. Wenn möglich als *_NEXT hinzufügen
  4. App für kurze Zeit alt und neu akzeptieren lassen
  5. Deployen und Health Checks prüfen
  6. Alten Wert widerrufen
  7. Git-Historie, CI-Logs, Monitoring-Logs und Prompts durchsuchen
  8. .env.example und Betriebsnotizen aktualisieren

Webhook-Secret, API-Key und DB-Passwort rotieren unterschiedlich. Halten Sie Owner, Zeitfenster und Rollback pro Typ fest.

Häufige Fehler

FehlerUrsacheGegenmaßnahme
.env committet.gitignore kam zu spätKeys sofort widerrufen; Git-Bereinigung reicht nicht
Secret in NEXT_PUBLIC_Öffentliches Präfix missverstandenPublic/private Namensregeln trennen
console.log(process.env)Eilige FehlersucheRedaction und Log-Review
Production startet nichtPflicht-Key fehltsrc/config/env.ts in CI ausführen
Lokaler Wert im Production-BuildBuild-time/runtime verwechseltPlattform-Injektion dokumentieren
Echter Key in Claude Code eingefügtPrompting mit Secret-Sharing verwechseltNur Namen und Regeln teilen

Direkt nutzbarer Claude-Code-Prompt

Implementiere Environment-Variable-Management für dieses Projekt.

Anforderungen:
- .env.example und .env.production.example erstellen
- .env, .env.* und .dev.vars* aus Git ausschließen
- Zod-Schema in src/config/env.ts hinzufügen und bei fehlenden/ungültigen Werten abbrechen
- Direkte process.env-Zugriffe in src/config/env.ts zentralisieren
- Secrets in Diagnose-Logs redigieren
- GitHub-Actions-Job hinzufügen, der Env-Validierung in Pull Requests ausführt
- Kurze Deployment-Notizen für Vercel, Cloudflare und Docker schreiben

Lies keine echten API-Keys oder Production-Datenbank-URLs. Arbeite nur mit Key-Namen und Validierungsregeln.

Fazit

Gutes Environment Management mit Claude Code bedeutet nicht, Secrets in den Chat zu kopieren. Es bedeutet, einen prüfbaren Vertrag zu implementieren: .env.example deklariert Keys, Zod validiert beim Start, Logs werden redigiert, CI/CD und Deployment-Plattformen injizieren echte Werte, und die Rotation ist vorbereitet.

ClaudeCodeLab bietet Claude-Code-Beratung, Team-Training, Repository-Sicherheitsreviews und Templates für Authentifizierung, Payments, CI/CD und Content Operations. Wer mit Claude Code schneller werden will, ohne Production-Keys zu verlieren, sollte diese Grundlage früh standardisieren.

In Masas Test-Repository hat dieses Muster vor dem Deployment drei Probleme gefunden: fehlender Production-Key, mögliches Logging eines Webhook-Secrets und eine veraltete .env.example. Die Zod-Startvalidierung ist einfach, macht Konfiguration aber zu einem durchsetzbaren Teamvertrag.

#Claude Code #Umgebungsvariablen #Secrets #Zod #CI/CD #TypeScript
Kostenlos

Kostenloses PDF: Claude-Code-Cheatsheet

E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.

Wir schützen Ihre Daten und senden keinen Spam.

Masa

Über den Autor

Masa

Engineer für praktische Claude-Code-Workflows und Team-Einführung.