985: Stop putting secrets in .env

Summary of 985: Stop putting secrets in .env

by Wes Bos & Scott Tolinski - Full Stack JavaScript Web Developers

47mMarch 9, 2026

Overview of 985: Stop putting secrets in .env

This Syntax episode (hosts Wes Bos & Scott Tolinski) features Theo Ephraim and Phil Miller from Varlock. The conversation critiques the common practice of storing plaintext secrets in .env files and .env.example copies, explains why that habit is dangerous (especially with AI coding agents), and walks through Varlock — a schema-driven, extensible tool/CLI that validates, injects, types, and protects environment configuration across dev, CI, and production.

Key problems with .env and .env.example

  • Plaintext secrets persist on disk, get forgotten, copied into Slack, repos, recordings, etc. — easy to leak.
  • Tutorials teach the bad pattern: "put secret in .env" as step 1.
  • .env.example is often inconsistent:
    • Mixed real values and placeholders (unclear which are real).
    • No single source of truth; docs, validation code, types, and examples drift out of sync.
  • Convenience wins over security — devs copy/paste because secret-management tools can be painful or costly.
  • AI agents exacerbate risk: they read local files and may exfiltrate secrets unless those secrets aren’t in plaintext.

Notable quote: “Everyone is still telling people to do that even though we know that it's wrong.”

What Varlock provides (architecture & features)

  • .env.schema file: a .env-style file augmented with JSDoc-like decorator comments to declare:
    • required/optional
    • sensitive
    • types (email, boolean, string, startsWith, etc.)
    • docs URL, icons, other metadata
  • Declarative fetch functions: call plugins to fetch secrets from external providers (1Password, AWS, GCP, Azure, Vercel, etc.).
  • Plugin model: many integrations exist and new plugins are easy to write.
  • Single source of truth: schema + values + validation + type generation + docs all unified.
  • Type generation: generates TypeScript types for env; easier IntelliSense than ad-hoc Zod setups.
  • Framework integrations: Vite, Next, Astro, etc. — can auto-inject and do proper build-time replacements.
  • Runtime helpers: an importable env helper that coerces types (booleans, numbers) and provides better ergonomics than raw process.env.
  • Hierarchical & monorepo support: import other schema files, override by environment (dev/staging/prod).
  • CLI + standalone binary: works for any language (varlock run, varlock load, etc.), so it’s not JS-only.

Security & leak protections

  • Redaction: patches global console methods to redact sensitive values in logs (currently JS-focused).
  • HTTP response protection: patches server response handling so returning a sensitive value in a response is blocked — prevents accidental leaks to clients.
  • Prevents client-side leaking in SSR/RSC setups by making it explicit which values are sensitive and ensuring build-time replacements reflect that.
  • Encourages using secrets managers (1Password recommended) as the source of truth; Varlock fetches from them rather than encouraging local plaintext.

Notable quote: “Make the easy way just secure.”

Workflow & developer experience

  • Progressive adoption:
    • Step 1: Add schema and run validation locally/CI to catch missing/invalid envs early.
    • Step 2: Swap to fetching from a secret store (1Password, secrets manager) and inject at runtime/build.
  • No need to prefix every command: framework integrations and auto-imports avoid forcing you to run varlock run npm run dev in most JS cases.
  • CLI usage: varlock run works well for ad-hoc commands (migrations, AI agent runs, CLI tools). For non-JS apps or custom flows you can use the standalone binary to inject envs.
  • CI/GitHub Actions: there's a lightweight action that runs varlock validation (varlock load) early in workflows so you fail fast on missing/incompatible envs and get redacted pretty output.
  • AI agents: varlock can inject the envs an agent (e.g., Claude) needs using varlock run and a centralized .env file (possibly in the home folder), enabling safer agent usage and limiting which envs you pass to the agent.

Language & ecosystem support

  • Primary deep integrations are JS/TS (console redaction, response patching, type generation).
  • Standalone binary makes Varlock usable from other languages and environments.
  • Type generation is currently for TypeScript, with other languages possible later.
  • Roadmap includes deeper language-specific integrations (redaction, response protection) for non-JS runtimes.

Opinions on secrets managers & best practices

  • OnePassword: recommended as a simple, developer-friendly source of truth (easy to unlock locally). Varlock has good 1Password integration.
  • Vault and other enterprise stores: workable but complex; Doppler and cloud provider secrets are options.
  • Best practice for constants vs env vars: use env vars for values that change by environment. Varlock’s schema makes putting more things in envs manageable because you get validation, types, and docs — reducing the friction that normally pushes people to hardcode constants.
  • Long-term goal: dynamic secrets, automated rotation, ephemeral keys — Varlock is exploring enterprise workflows like rotation and dynamic keys.

Product & openness

  • Varlock is open source; project intends to remain trustworthy (no “rug pull”). They have investor funding and may build hosted/enterprise features in the future (logs, policies, rotation).
  • Goal: a free, usable tool for solo devs that scales into teams and enterprises.

Tips, demos & integrations mentioned

  • varlock.dev — project homepage (mentioned on the show).
  • Sentry sponsor shout-out: use sentry.io/syntax for production error visibility.
  • VS Code “cloak” mentioning and existing 1Password VS Code extension for hiding secret values in the editor.
  • GitHub Actions: use Varlock action to validate env schema early in workflows.

Notable quotes & takeaways

  • “The only real safe way to ensure [AI agents] are not sent up to OpenAI is to get them out of plain text altogether.”
  • “If I can avoid using this at all, I'm going to.” (about struggling with env ergonomics)
  • Practical rule of thumb: put values that vary by environment into envs; use a schema to make it sane, typed, and documented.

Actionable recommendations (what to do next)

  • Stop checking plaintext .env files into repos; remove sensitive values from local .env files.
  • Add a schema for your environment variables (validate early) — prevents runtime surprises.
  • Adopt a secret store (1Password or similar) as your source of truth and configure your tooling to fetch from it.
  • Integrate env validation into CI to fail fast and show redacted diagnostic output.
  • Use tools (Varlock or equivalents) that:
    • unify schema, types, and documentation,
    • prevent accidental leaks (logs, HTTP responses),
    • support safe injection for AI agents and CLI workflows.
  • If using JS/TS, consider Varlock’s framework integrations to reduce friction.

Final notes, plugs & guest picks

  • Varlock is open-source; contributors/stars are encouraged (guests requested stars on GitHub).
  • Guests’ “sick picks” and plugs: Bella.io audio modules, the Wonder Man show (Disney/Marvel), Theo’s howtostore site, Phil’s music at nauticalartifacts.bandcamp.com.

If you want to immediately reduce leakage risk: remove plaintext production secrets from local .env files, add a schema + CI validation, and centralize secrets into a password manager or secrets store that Varlock (or similar tooling) can fetch from.