Managing secrets across many apps without copy and paste

How to organize environment variables and shared secrets across services and environments, with scoping, rotation and auditing.

With three services, copying the same database URL or API key into each one is fine. With thirty, it becomes the reason a rotated key breaks half your apps on a Friday. A little structure solves this.

Separate config from secrets

Config is non sensitive: feature flags, URLs, log levels. Secrets are sensitive: passwords, API keys, signing keys. Both can be environment variables, but secrets need stricter handling: masking in the UI, limited read access and rotation.

Define scopes

Most values naturally belong to a scope:

  • Workspace or organization: shared third party keys such as an email provider or error tracker
  • Project: a database URL shared by the API and worker of one product
  • Server: values tied to a host, such as an internal registry address
  • Service: anything only one service uses

Store each value once at the right scope and reference it from services. When it changes, it changes everywhere.

Naming conventions

Pick a convention and stick to it: uppercase with underscores, a prefix per integration (STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET), and no environment in the name. Use separate environments, not PROD_DATABASE_URL and STAGING_DATABASE_URL in the same place.

Never commit secrets

Keep .env in .gitignore. Commit a .env.example with names and placeholder values so new developers know what is needed. Add a secret scanner to CI to catch accidents.

Build time vs run time

Values passed at build time can end up in image layers or client side bundles. Pass secrets at run time only. For frontends, remember that anything prefixed for the browser (such as NEXT_PUBLIC_) is public by definition.

Rotation

Plan for rotation before you need it:

  1. Create the new key at the provider
  2. Update the shared variable
  3. Redeploy services that use it
  4. Verify, then revoke the old key

If a value is shared from one place, step 2 is one edit instead of thirty.

Access

Not everyone who can deploy needs to read production secrets. Allow developers to set or replace values without reading existing ones if your tooling supports it. Log changes to secrets with who made them.

Cleanup

Unused variables pile up. Review periodically and remove values no service references. Stale secrets are still secrets an attacker can use.

When to use a dedicated secrets manager

If you need dynamic credentials, fine grained policies or compliance reporting, use a secrets manager such as Vault, Infisical or a cloud provider’s service, and inject values at run time. For most small teams, scoped shared variables in the deployment platform are enough.

On Peon, shared variables can be scoped to a workspace, project or server, and the environment variables documentation explains how they combine with per service values.

Disclosure: I work on Peon.


Write a comment