Profiles
What Are Profiles?
Section titled “What Are Profiles?”Profiles are named configurations that define how secrets behave in different environments. They specify which secrets are required vs optional, provide safe defaults for development, and enforce strict requirements for production.
The default profile is an optional shared base. When it exists, other
profiles inherit its secret declarations unless an individual declaration opts
out, and fill omitted fields from matching declarations. Use default for
settings that really are common—not as another name for development. A project
whose profiles are independent can omit default; SecretSpec 0.19+ can also
keep individual default secrets local.
If a manifest omits default, callers must select an existing profile with
--profile, SECRETSPEC_PROFILE, or their user config; the final fallback name
is still default.
Basic Usage
Section titled “Basic Usage”Define profiles in your secretspec.toml:
[profiles.default]DATABASE_URL = { description = "PostgreSQL connection", required = true }API_KEY = { description = "External API key", required = true }
[profiles.development]# Inherits DATABASE_URL and API_KEY from default, only overriding their requirementsDATABASE_URL = { required = false, default = "postgresql://localhost:5432/myapp_dev" }API_KEY = { required = false, default = "dev-key-12345" }DEBUG = { description = "Enable debug mode", required = false, default = "true" }
[profiles.production]# Inherits all secrets from default profile# Only need to add production-specific secretsSENTRY_DSN = { description = "Error tracking", required = true }Selecting Profiles
Section titled “Selecting Profiles”SecretSpec resolves the active profile in this order:
- Command line:
--profile production(highest priority) - Environment variable:
SECRETSPEC_PROFILE=staging - User config: Default profile in
~/.config/secretspec/config.toml - Fallback:
defaultprofile
# Use specific profile$ secretspec check --profile development✓ DATABASE_URL - PostgreSQL connection (using default)✓ API_KEY - External API key (using default)
# Set via environmentexport SECRETSPEC_PROFILE=productionsecretspec run -- npm startProfile Inheritance in Detail
Section titled “Profile Inheritance in Detail”When using profiles, inheritance works as follows:
- Base definition in default: Define all your secrets with their descriptions and base requirements in the
defaultprofile - Override only what changes: Other profiles only need to specify the properties that differ from default
- Complete override: When a profile defines a secret, it can override any or all properties (
required,default,description) - Profile-specific secrets: Secrets not in the default profile can be added to any profile
Descriptions participate in the same field-by-field merge, so an override does not need to repeat one:
[profiles.default]SOME_SECRET = { description = "What this secret controls", required = false }
[profiles.production]SOME_SECRET = { required = true }Local-only secrets (0.19+)
Section titled “Local-only secrets (0.19+)”Set inherit = false on a default secret that must not automatically appear in
other profiles:
[profiles.default]LOCAL_DUMMY_TOKEN = { description = "Dummy token used by local development", default = "dummy", inherit = false }SHARED_TOKEN = { description = "Token used in every environment", required = false }
[profiles.production]SHARED_TOKEN = { required = true } # description inheritedPRODUCTION_TOKEN = { description = "Production service token", required = true }
[profiles.deploy]DEPLOY_TOKEN = { description = "Deployment credential", required = true }Here, LOCAL_DUMMY_TOKEN exists only in default, while SHARED_TOKEN is
inherited normally. A profile can explicitly redeclare a local-only secret; it
then inherits omitted fields from the matching default declaration. On secrets
declared outside default, the field has no effect. Omitting inherit
preserves existing behavior.
Profiles, Scopes, Providers, and Extends
Section titled “Profiles, Scopes, Providers, and Extends”These features solve different dimensions of a configuration:
- A profile chooses an environment or context. It controls requiredness,
defaults, provider routes, references, and the
{profile}storage namespace. - A scope selects which secrets one service or task receives from the effective profile. It does not create another environment.
- A secret’s providers choose where its value is read and written. Provider chains are also the least-privilege boundary: a process only needs access to the stores used by the secrets in its scope.
extendsmerges separatesecretspec.tomlfiles. Use it to share manifests across projects, not to express relationships among several profiles in one small manifest.
For an application with development and production environments plus
app, public, and deploy consumers, profiles normally model the two
environments, scopes model the three consumers, and per-secret provider chains
route each value to the appropriate store.
Profile-Level Defaults
Section titled “Profile-Level Defaults”To reduce repetition when multiple secrets in a profile share the same settings, use the profiles.<name>.defaults section:
[providers]prod_vault = "onepassword://Production"keyring = "keyring://"
[profiles.production.defaults]providers = ["prod_vault", "keyring"]required = true
[profiles.production]DATABASE_URL = { description = "Production DB" }API_KEY = { description = "API Key" }SENTRY_DSN = { description = "Error tracking" }Profile defaults apply to all secrets in that profile unless explicitly overridden. The precedence order is:
- Secret-level configuration (highest priority) — explicit settings in the secret definition
- Profile defaults — from
profiles.<name>.defaults - Profile inheritance — inherited from default profile
- Global defaults (lowest priority) — from CLI, environment, or global config
This is particularly useful for setting common provider fallback routes, requirements, or defaults across all secrets in a profile.
Practical Example
Section titled “Practical Example”A web application with different requirements per environment:
[project]name = "web-app"revision = "1.0"
[profiles.default]DATABASE_URL = { description = "PostgreSQL connection", required = true }REDIS_URL = { description = "Redis for caching", required = true }JWT_SECRET = { description = "JWT signing key", required = true }
[profiles.development]# Inherits all secrets from default, just adding defaultsDATABASE_URL = { default = "postgresql://localhost:5432/webapp_dev" }REDIS_URL = { default = "redis://localhost:6379/0" }JWT_SECRET = { default = "dev-secret-change-in-prod" }HOT_RELOAD = { description = "Enable hot reload", required = false, default = "true" }
[profiles.production]# Inherits DATABASE_URL, REDIS_URL, JWT_SECRET from default# Only adds production-specific secretsSENTRY_DSN = { description = "Error tracking", required = true }SSL_CERT = { description = "SSL certificate path", required = true }