Tips & Tricks (Diperbarui: 2/6/2026)

Environment Variable di Claude Code: .env, Zod, Secrets, dan Deploy Aman

Kelola environment variable dan Secrets dengan Claude Code: .env.example, validasi Zod, CI/CD, redaction, dan rotasi.

Environment Variable di Claude Code: .env, Zod, Secrets, dan Deploy Aman

Saat pemula meminta Claude Code membuat login, pembayaran, webhook, atau integrasi AI, bug production pertama sering bukan berasal dari UI. Masalah biasanya muncul di konfigurasi: URL database kurang, key staging dipakai di production, WEBHOOK_SECRET tercetak di log CI, atau API key asli ikut ter-commit ke GitHub.

Panduan ini memberikan pola yang siap diimplementasikan untuk mengelola environment variable dan Secrets dengan Claude Code. Environment variable adalah nilai yang diberikan ke aplikasi saat runtime, seperti PORT atau APP_ORIGIN. Secret adalah nilai yang bisa disalahgunakan jika bocor, seperti ANTHROPIC_API_KEY, DATABASE_URL, atau WEBHOOK_SECRET. Secret sering dikirim lewat environment variable, tetapi perlakuannya harus lebih ketat.

Untuk konfigurasi Claude Code sendiri, gunakan referensi resmi Claude Code environment variables. Untuk validasi konfigurasi aplikasi, kita memakai Zod. Untuk CI/CD dan deploy, rujuk GitHub Actions secrets, Vercel environment variables, Cloudflare Workers variables and secrets, dan Docker secrets. Platform bisa berbeda, tetapi prinsipnya sama: simpan nama key dan aturan validasi di code, bukan nilai secret.

Untuk konteks keamanan yang lebih luas, baca juga praktik keamanan Claude Code dan JWT authentication dengan Claude Code.

Perlakukan .env sebagai kontrak

File .env sangat berguna, tetapi jangan biarkan menjadi catatan pribadi tiap developer. Tim membutuhkan tiga lapis kontrol:

  • Deklarasi: .env.example mencatat key yang wajib ada
  • Validasi: Zod menggagalkan startup jika nilai hilang atau format salah
  • Operasi: CI/CD dan production menginjeksi nilai dari Secrets platform
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

Intinya, semua entry point lewat schema yang sama. Claude Code perlu menerima nama key, aturan validasi, dan perilaku saat gagal. Jangan berikan nilai production asli di prompt.

Use case konkret

Use caseNilai umumMode gagal
Development lokalAPP_ORIGIN, DATABASE_URL, ANTHROPIC_API_KEYAplikasi hanya jalan di laptop satu orang
Verifikasi webhookSTRIPE_WEBHOOK_SECRET, WEBHOOK_SECRETRequest palsu diterima
Testing CICI_DATABASE_URL, TEST_API_KEYPR lolos, tetapi deploy gagal
Deploy productionDATABASE_URL, SESSION_SECRET, APP_ORIGINSalah DB, cookie rusak, credential bocor
Rotasi secretANTHROPIC_API_KEY_NEXTKey lama yang bocor tetap valid terlalu lama

Dalam workflow Masa di ClaudeCodeLab, peningkatan terbesar bukan hanya membuat .env.example, tetapi membuat aplikasi menolak startup saat kontrak konfigurasi belum lengkap. Masalah yang biasanya muncul saat deploy berubah menjadi failure yang bisa direview di pull request.

1. Pisahkan file lebih dulu

.env.example adalah dokumentasi, bukan tempat nilai asli. .env.local hanya untuk mesin lokal. .env.production.example adalah checklist production tanpa nilai secret.

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

Placeholder bukan default yang aman. Placeholder hanya menandakan bahwa nilai harus disediakan dari tempat lain.

2. Validasi saat startup dengan Zod

Di Node.js, environment variable masuk sebagai string. PORT=3000 pun tetap string, jadi z.coerce.number() diperlukan untuk konversi dan validasi range.

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

Tes lokal:

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

Lalu minta Claude Code mencari akses process.env yang tersebar:

Cari semua pembacaan process.env langsung di repository ini.
Hanya src/config/env.ts yang boleh membaca process.env langsung.
Untuk file lain, usulkan perubahan agar mengimpor env dari src/config/env.ts.
Jangan mencetak secrets di logs, errors, atau test snapshots.

3. Redact sebelum logging

Kebocoran secret tidak hanya terjadi di Git. CI logs, output debug, error monitoring, rekaman layar, dan terminal output yang ditempel ke Claude Code juga bisa menjadi jalur bocor.

// 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 adalah pagar terakhir. Desain log yang lebih baik adalah tidak pernah menerima nilai secret sejak awal.

4. Inject dari CI/CD Secrets

GitHub Actions bisa memberikan repository, environment, atau organization secrets ke workflow. Jangan gunakan credential production untuk test PR biasa; buat nilai khusus CI dengan scope kecil.

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

Jangan berasumsi semua workflow menerima secrets. Fork PR, reusable workflow, dan event otomatis bisa memiliki batasan. Buat job validasi eksplisit dan jangan menulis secret ke file yang dihasilkan.

5. Catatan Docker, Vercel, Cloudflare

Di Docker, jangan menulis ENV API_KEY=... di Dockerfile. Untuk local testing, env file bisa dipakai; untuk production, gunakan secret store atau orchestrator runtime.

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

Jika runtime memberikan secret sebagai file, dukung konvensi 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();
}

Di Vercel, pisahkan Production, Preview, dan Development. Perhatikan prefix yang terekspos ke browser seperti NEXT_PUBLIC_. Di Cloudflare Workers, nilai bisa datang lewat bindings, parameter env, atau platform Secrets. Jangan mengklaim satu contoh cocok untuk semua runtime; jadikan schema sebagai sumber kebenaran dan dokumentasikan titik injection per platform.

Review konfigurasi environment untuk Vercel, Cloudflare, dan Docker.
Jangan membaca atau meminta nilai production asli.
Cek required key names, batas public vs secret, build-time vs runtime, dan catatan rotasi.

6. Tulis playbook rotasi lebih dulu

Rotasi Secrets jangan dibuat mendadak saat incident:

  1. Identifikasi scope: service, environment, permission, owner
  2. Buat nilai baru dengan permission minimum
  3. Tambahkan sebagai *_NEXT jika dual-running memungkinkan
  4. Deploy support untuk nilai lama dan baru dalam window singkat
  5. Alihkan traffic dan cek health check
  6. Revoke nilai lama
  7. Cari exposure di Git history, CI logs, monitoring logs, dan prompts
  8. Update .env.example dan catatan operasional

Webhook secret, API key, dan password database punya mekanisme rotasi berbeda. Tulis owner, window, dan rollback untuk masing-masing.

Kegagalan umum

KegagalanPenyebabPerbaikan
.env ter-commit.gitignore terlambat ditambahkanRevoke key segera; membersihkan history saja tidak cukup
Secret masuk NEXT_PUBLIC_Prefix publik tidak dipahamiPisahkan naming rule public/private
console.log(process.env)Debug terburu-buruPakai redaction dan review log
Production gagal startRequired key belum disetJalankan src/config/env.ts di CI
Nilai lokal masuk build productionBuild-time/runtime tercampurDokumentasikan injection per platform
Key asli ditempel ke Claude CodePrompt disamakan dengan secret sharingBagikan nama key dan rules saja

Prompt Claude Code siap pakai

Implementasikan environment variable management untuk project ini.

Requirements:
- Buat .env.example dan .env.production.example
- Pastikan .env, .env.*, dan .dev.vars* tidak masuk Git
- Tambahkan Zod schema di src/config/env.ts dan gagal startup jika nilai hilang/invalid
- Centralize direct process.env reads di src/config/env.ts
- Redact secrets di diagnostic logs
- Tambahkan GitHub Actions job yang menjalankan env validation pada pull requests
- Tulis catatan deploy singkat untuk Vercel, Cloudflare, dan Docker

Jangan membaca API key asli atau production database URL. Kerjakan hanya dari nama key dan validation rules.

Kesimpulan

Menggunakan Claude Code untuk environment management bukan berarti menempel secrets ke chat. Cara yang benar adalah membuat kontrak yang bisa divalidasi: .env.example mendeklarasikan key, Zod memvalidasi saat startup, logs di-redact, CI/CD dan platform menginjeksi nilai asli, dan tim punya playbook rotasi.

ClaudeCodeLab menyediakan konsultasi Claude Code, training tim, review keamanan repository, serta template untuk authentication, payments, CI/CD, dan content operations. Jika tim Anda ingin bergerak lebih cepat dengan Claude Code tanpa membocorkan production keys, environment management adalah salah satu fondasi pertama yang perlu distandarkan.

Di repository uji Masa, pola ini menemukan tiga masalah sebelum deploy: production key yang belum ada, Webhook secret yang berpotensi masuk log, dan .env.example yang sudah usang. Validasi startup dengan Zod sederhana, tetapi mengubah konfigurasi dari pengetahuan pribadi menjadi kontrak tim yang bisa dipaksa.

#Claude Code #environment variable #Secrets #Zod #CI/CD #TypeScript
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.