Documentation
Everything you need to manage secrets with envsec.
Installation
envsec requires Node.js 18 or later. Install globally via npm:
npm install -g envsecOr run directly without installing:
npx envsecIf you use mise as a version manager:
mise use -g npm:envsecQuick Start
Store your first secret. The -c flag sets the context — a label for grouping related secrets.
# Store a secret
envsec -c myapp.dev add api.key -v "sk-abc123"
# Retrieve it
envsec -c myapp.dev get api.key
# List all secrets in the context
envsec -c myapp.dev list
# Run a command with secret interpolation
envsec -c myapp.dev run 'curl -H "Auth: {api.key}" https://api.example.com'Requirements
macOS
No extra dependencies. Uses the built-in Keychain via the security CLI tool.
Linux
Requires libsecret-tools (provides the secret-tool command), which talks to GNOME Keyring, KDE Wallet, or any Secret Service API provider via D-Bus.
# Debian / Ubuntu
sudo apt install libsecret-tools
# Fedora
sudo dnf install libsecret
# Arch
sudo pacman -S libsecretWindows
No extra dependencies. Uses the built-in Windows Credential Manager via cmdkey and PowerShell.
envsec add
Store a secret in the OS credential store.
# Inline value
envsec -c myapp.dev add api.key --value "sk-abc123"
# Interactive masked prompt (omit --value)
envsec -c myapp.dev add api.key
# With expiry duration
envsec -c myapp.dev add api.key -v "sk-abc123" --expires 30d
# Supported units: m (minutes), h (hours), d (days),
# w (weeks), mo (months), y (years)
# Combinable: 1y6mo, 2w3d, 1d12h
envsec -c myapp.dev add api.key -v "sk-abc123" -e 6moenvsec get
Retrieve a single secret value.
envsec -c myapp.dev get api.keyenvsec list
List all secrets in a context, or list all contexts.
# List secrets in a context
envsec -c myapp.dev list
# List all contexts (without -c)
envsec listenvsec search
Search secrets or contexts with glob patterns.
# Search secrets within a context
envsec -c myapp.dev search "api.*"
# Search contexts by pattern
envsec search "myapp.*"envsec delete
Remove a secret from the credential store.
envsec -c myapp.dev delete api.key
# Skip confirmation prompt
envsec -c myapp.dev delete api.key --yes
# Alias
envsec -c myapp.dev del api.keyenvsec run
Execute a command with secret interpolation. Placeholders like {key} are resolved and injected as environment variables — values never appear in ps output.
# Run with secret interpolation
envsec -c myapp.dev run 'curl {api.url} -H "Authorization: Bearer {api.token}"'
# Save the command for later
envsec -c myapp.dev run --save --name deploy 'kubectl apply -f - <<< {k8s.manifest}'envsec cmd
Manage saved commands.
# List saved commands
envsec cmd list
# Run a saved command
envsec cmd run deploy
# Override context at execution time
envsec cmd run deploy --override-context myapp.prod
# Search saved commands
envsec cmd search psql
# Delete a saved command
envsec cmd delete deployenvsec env
Export secrets as shell environment variable statements.
# bash/zsh
eval $(envsec -c myapp.dev env)
# fish
envsec -c myapp.dev env --shell fish
# powershell
envsec -c myapp.dev env --shell powershell
# Unset exported variables
eval $(envsec -c myapp.dev env --unset)Keys are converted to UPPER_SNAKE_CASE (e.g. api.token → API_TOKEN).
envsec env-file
Export secrets to a .env file.
# Default output: .env
envsec -c myapp.dev env-file
# Custom output path
envsec -c myapp.dev env-file --output .env.localenvsec load
Import secrets from a .env file into a context.
# Import from .env
envsec -c myapp.dev load
# Custom input file
envsec -c myapp.dev load --input .env.local
# Overwrite existing secrets
envsec -c myapp.dev load --forceenvsec audit
Check for expired or expiring secrets.
# Default window: 30 days
envsec -c myapp.dev audit
# Custom window
envsec -c myapp.dev audit --within 7d
# Only already-expired
envsec -c myapp.dev audit --within 0d
# Audit all contexts
envsec audit
# JSON output
envsec -c myapp.dev audit --jsonContexts
A context is a free-form label for grouping secrets — e.g. myapp.dev, stripe-api.prod, work.staging. Most commands require a context specified with --context (or -c).
Keys must contain at least one dot separator (e.g. service.account) which maps to the credential store's service/account structure.
Custom Database Path
By default, metadata is stored at ~/.envsec/store.sqlite. Override with --db or the ENVSEC_DB environment variable.
# Project-local database
envsec --db ./local-store.sqlite -c myapp.dev list
# Via environment variable
export ENVSEC_DB=/shared/team/envsec.sqlite
envsec -c myapp.dev listShell Completions
Tab completion for bash, zsh, fish, and sh.
# Bash (add to ~/.bashrc)
eval "$(envsec --completions bash)"
# Zsh (add to ~/.zshrc)
eval "$(envsec --completions zsh)"
# Fish (add to ~/.config/fish/config.fish)
envsec --completions fish | sourceSecurity Model
envsec delegates encryption to your OS native credential store. It never invents its own crypto. Secret values go straight from your terminal into the OS credential store — they are never written to config files, logs, or intermediate storage.
The list and search commands display key names only — values are never printed. The run command injects secrets as environment variables of the child process rather than interpolating them into the command string, keeping values out of ps output and shell history.
The metadata directory (~/.envsec/) is created with 0700 permissions and the SQLite database with 0600, limiting access to the owning user.
Known Limitations
- The SQLite database stores key names, context names, and timestamps — never secret values, but enough to reveal what secrets exist.
- The
env-filecommand writes secret values to a .env file on disk. Treat the output file accordingly. - The
runcommand passes templates through /bin/sh. Only run templates you wrote or trust. - Any process running as your OS user can read all secrets across all contexts.
- On Linux, envsec depends on an active D-Bus session and a keyring daemon.