CLI Guide
Security & Access
Everything envv does at runtime — token storage, caching, child process management — is designed so secrets never persist on disk in plaintext and never leak across processes.
Token Storage
When you run envv login --token, the API key is written to your operating system's native credential store via the keyring library:
- macOS: Keychain (
service=envvault,account=session-token) - Linux: Secret Service / GNOME Keyring
- Windows: Credential Manager
On systems without a keyring (some headless Linux servers, CI runners), the CLI falls back to ~/.envv/config.json with restrictive file permissions.
To override token discovery, export ENVVAULT_TOKEN. The env var always wins:
export ENVVAULT_TOKEN=evk_xxxxxxxxxxxxxxxxx
envv run -- ./my-serviceEncrypted Local Cache
When you opt in with --env-cache, the merged environment is cached at ~/.envv/cache/:
- Encryption: AES-256-GCM with a key derived from your token + machine identifier.
- TTL: 24 hours per entry.
- Eviction: files older than 7 days are deleted on next CLI run.
Without --env-cache, secrets exist only in process memory for the duration of your child process.
Edge Encryption
Organization secrets are encrypted on Cloudflare's edge before storage in D1. Plaintext never touches the database — encryption and decryption happen in-memory inside a Worker. The CLI receives plaintext only over the authenticated HTTPS request.
The same secret can hold different values per environment. Setting an existing key auto-increments its version so a full audit trail is preserved.
Self-Hosted & Custom Endpoints
Point the CLI at a self-hosted backend with ENVVAULT_API_URL:
export ENVVAULT_API_URL=https://envvault.internal.acme.corp/api/v1/cli
export ENVVAULT_TOKEN=evk_xxxxxxxxxxxxxxxxx
envv run -- ./my-serviceUseful for air-gapped deployments or custom compliance environments. The CLI falls back to https://api.envvault.com/api/v1/cli when the variable is unset.
Process Behavior
envv run forwards SIGINT, SIGTERM, and SIGHUP to the child process. Ctrl-C in your shell cleanly terminates the wrapped command — no orphaned processes.
Variables already present in your shell take precedence over EnvVault values. CI runners that inject their own credentials are never silently overridden.
If the requested port is busy, envv run finds the next free port starting at 3000 and rewrites PORT, APP_URL, and NEXT_PUBLIC_APP_URL for the child.
Without --env-cache, the only on-disk artifacts are the keyring entry and .envv.json (project ID + name only). Secrets exist in memory for the lifetime of the child process.
Best Practices
Per-user API keys for humans, scoped keys for CI. Issue separate API keys with project scopes and short expiries for automation.
IP allowlist your CI runners. Lock service-account keys to known IP ranges where possible.
Rotate on offboarding. When a teammate leaves, revoke their personal keys and rotate any sensitive secrets they could read.
Don't commit secrets. Never commit raw values or .env files generated by envv generate. The dashboard's API key flow exists so CI can fetch them at deploy time.
Audit reads. Spot-check /dashboard/audit for unexpected SECRET_READ events.
Incident Response
If you suspect a leaked API key or compromised secret:
- Revoke the key at /dashboard/api-keys — takes effect immediately.
- Rotate the affected secret(s):
envv secrets set KEY=NEW_VALUE. - Restart any services that read the secret with
envv docker-run --restart. - Inspect the audit log for the time window of suspected exposure.