The alias registry is the document that maps human-readable alias names to fully-qualified backend URIs. It is the single source of truth for where every secret lives.
A flat key-value TOML document stored in any backend you control:
# stored at aws-ssm-platform:///secretenv/registry
stripe-key = "1password-work://payments/stripe/api_key"
db-url = "aws-ssm-dev:///myapp/dev/db_url"
datadog-api-key = "1password-work://engineering/datadog/api_key"
redis-url = "aws-ssm-dev:///myapp/dev/redis_url"
vault-token = "vault-eng://secret/myapp/vault_token"Keys are alias names. Values are backend URIs using named instances as the scheme.
Every command resolves which registry to use in this order, the first hit wins, and there is no implicit fallback at the bottom:
1. --registry <name-or-uri> explicit, per-invocation
2. SECRETENV_REGISTRY=<name-or-uri> CI / shell-session override
3. [registries.default] in config machine default
4. hard error no assumption is made
The --registry value (and SECRETENV_REGISTRY) is disambiguated by content: if it contains :// it's a direct URI (a single source, no cascade). Otherwise it's a name looked up in [registries.<name>]. SECRETENV_REGISTRY is the canonical mechanism for CI, where no config file lives on the runner.
secretenv run -- npm start # [registries.default]
secretenv run --registry dev -- npm start # named registry (may cascade)
secretenv run --registry aws-ssm-dev:///secretenv/reg -- ... # direct URI, single sourceA registry configuration can cascade across multiple source documents. Sources are checked in order, first match wins. Entries in later sources that share a key with an earlier source are silently shadowed.
# config.toml
[registries.dev]
sources = [
"aws-ssm-dev:///secretenv/dev-registry", # team-specific, checked first
"aws-ssm-platform:///secretenv/org-registry", # org-wide fallback
]Use cases for cascading:
- Team-specific aliases that override org-wide defaults
- Per-environment aliases alongside shared infrastructure aliases
- Gradual migration from one registry to another
All registry commands accept --registry <name-or-uri> to target a specific registry. Without it, the active registry (from --registry flag, SECRETENV_REGISTRY, or [registries.default]) is used.
Shows all aliases across all sources in the active registry, with provenance and shadowing clearly marked.
secretenv registry list
secretenv registry list --registry devRegistry: dev (2 sources)
─────────────────────────────────────────────────────────────────────
aws-ssm-dev:///secretenv/dev-registry [source 1]
┌─────────────────────────────────────────────────────────────────┐
│ stripe-key → aws-ssm-dev:///myapp/dev/stripe_key │
│ db-url → aws-ssm-dev:///myapp/dev/db_url │
│ redis-url → aws-ssm-dev:///myapp/dev/redis_url │
└─────────────────────────────────────────────────────────────────┘
aws-ssm-platform:///secretenv/org-registry [source 2]
┌─────────────────────────────────────────────────────────────────┐
│ stripe-key → 1password-work://payments/stripe ↑ shadowed by source 1
│ datadog-api-key → 1password-work://engineering/datadog │
│ vault-token → vault-eng://secret/myapp/vault_token │
└─────────────────────────────────────────────────────────────────┘
Resolved aliases: 5 (1 shadowed)
Shows what a single alias resolves to, including which source it came from and what it shadows.
secretenv registry get stripe-key
secretenv registry get stripe-key --registry devstripe-key
resolved by: aws-ssm-dev:///secretenv/dev-registry [source 1]
points to: aws-ssm-dev:///myapp/dev/stripe_key
shadowing: 1password-work://payments/stripe (source 2)
Writes an alias to the registry. Always writes to source[0] of the active registry.
secretenv registry set stripe-key "1password-work://payments/stripe/api_key"
secretenv registry set db-url "aws-ssm-prod:///myapp/prod/db_url" --registry prod✓ Written to source 1: aws-ssm-dev:///secretenv/dev-registry
stripe-key → 1password-work://payments/stripe/api_key
To write to a specific source, pass a direct URI:
secretenv registry set stripe-key "..." \
--registry aws-ssm-platform:///secretenv/org-registryValidation: the value must be a valid backend URI (contains :// with a recognized scheme). Hard error otherwise.
Removes an alias from source[0] of the active registry.
secretenv registry unset old-deprecated-key
secretenv registry unset old-key --registry dev✓ Removed from aws-ssm-dev:///secretenv/dev-registry
old-key (was → aws-ssm-dev:///myapp/dev/old_key)
If the alias only exists in a downstream source, secretenv warns rather than silently doing nothing:
⚠ 'datadog-api-key' not found in source 1 (aws-ssm-dev:///secretenv/dev-registry)
found in source 2 (aws-ssm-platform:///secretenv/org-registry)
to remove from source 2, pass it explicitly:
secretenv registry unset datadog-api-key \
--registry aws-ssm-platform:///secretenv/org-registry
Shows version history of the secret an alias resolves to, where the backend supports it. Output is most-recent-first.
secretenv registry history <alias>
secretenv registry history <alias> --registry prod
secretenv registry history <alias> --jsonalias: stripe-key
resolved: vault-eng:///secret/payments/stripe
v3 2026-04-10 ...
v2 2026-03-20 ...
v1 2026-03-01 ...
--json emits machine-readable output. Backends with no native history API return an error naming the backend type so the CLI can distinguish unsupported from a real failure.
Backend support:
| Backend | History support |
|---|---|
| AWS SSM SecureString | ✓ Parameter versions via SSM API |
| HashiCorp Vault KV v2 | ✓ Native versioning |
| Local file | ✓ git log (requires the file to be under a git repo) |
| 1Password | ✗ Not implemented |
| AWS Secrets Manager | ✗ Not implemented |
| All other backends | ✗ Not implemented |
Generates the onboarding command for a new team member based on the active registry configuration.
secretenv registry inviteShare this with new team members:
secretenv setup aws-ssm-platform:///secretenv/org-registry
Or with a distribution profile (pre-configures all backends and registries):
curl -sfS https://secretenv.io/install.sh | sh -s -- --profile acme-corp
For teams managing infrastructure as code, the registry document can be managed via Terraform or any tool that can write to a backend. secretenv does not require using the CLI to manage registry content; it only needs to be able to read the document at runtime.
The registry document format is a flat TOML key-value structure:
alias-name = "backend-instance://path/to/secret"Via Terraform (AWS SSM):
resource "aws_ssm_parameter" "secretenv_registry" {
name = "/secretenv/org-registry"
type = "SecureString" # always SecureString, never String
value = jsonencode({
"stripe-key" = "1password-work://payments/stripe/api_key"
"db-url" = "aws-ssm-prod:///myapp/prod/db_url"
"datadog-api-key" = "1password-work://engineering/datadog/api_key"
})
}Note: when managing the registry via Terraform, the alias-to-path mappings are in version-controlled Terraform state. This is an operational choice: the alias values (backend paths) are organizational configuration, not secret values, so this tradeoff is similar to managing Kubernetes ExternalSecrets manifests in code.
The registry document maps alias names to backend paths. It does not contain secret values. However its access controls matter.
Treat the registry's access controls equivalently to your most sensitive secret.
If an attacker can read the registry, they learn your secrets topology: which backends you use, what paths your secrets live at, your naming conventions. They do not get secret values. But if they already have authenticated access to the registry backend, they likely have broader backend access anyway.
Recommended storage:
| Backend | Recommended configuration |
|---|---|
| AWS SSM | SecureString type with KMS encryption. IAM policy: ssm:GetParameter scoped to the registry path only, for the identities that need it. |
| HashiCorp Vault | KV v2 with a policy that grants read access to the registry path. Separate policy from application secret access. |
| 1Password | Dedicated vault for secretenv registry. Share only with team leads and platform engineers, not all developers. |
| Local file | chmod 600. For solo developers only. |
No convention is enforced by secretenv. Recommendations:
- Use kebab-case:
stripe-key,prod-db-url,datadog-api-key - Keep alias names environment-agnostic where possible. Route environments via registry selection, not alias naming
- Use consistent naming across services. If multiple services need a shared Datadog key, one alias shared via the org registry is better than
service-a-datadog-keyandservice-b-datadog-key - Prefix team-specific aliases if co-existing with an org registry:
payments-stripe-keyvs org-levelstripe-key