# Declarative Configuration

> Understanding secretspec.toml and its declarative approach

SecretSpec uses `secretspec.toml` to declare what secrets your application needs, separating requirements from storage mechanisms for portability across environments.

## Basic Structure

```toml
[project]
name = "my-app"
revision = "1.0"
extends = ["../shared/common"]  # Optional: inherit from other configs


[profiles.default]
DATABASE_URL = { description = "PostgreSQL connection string", required = true }
API_KEY = { description = "External API key", required = true }
SESSION_SECRET = { description = "Session signing secret", required = true, type = "password", generate = true }
```

## Secret Declarations

Each secret is declared with configuration options:

```toml
SECRET_NAME = {
  description = "Human-readable explanation",  # Required: shown in prompts
  required = true,                            # Optional: defaults to true
  default = "value"                           # Optional: fallback if not set
}
```

**Options:**

* `description`: Explains the secret’s purpose (required in the `default` profile; profile overrides inherit it when omitted)
* `required`: Whether the secret must be provided (default: `true`)
* `default`: Fallback value for optional secrets
* `composed` (0.16+): Derive a read-only value from other declared secrets (see [Composed Secrets](/concepts/composed-secrets/) for the strict template and dependency semantics)
* `type`: Secret type for auto-generation (`password`, `hex`, `base64`, `uuid`, `command`, `rsa_private_key`, `openpgp_private_key` (0.21+), `ssh_private_key` (0.21+); `passphrase`, `mnemonic`, `wireguard_private_key`, `jwk_private_key`, `age_identity`, and `x509_identity` require 0.22+)
* `generate`: Enable auto-generation when the secret is missing (`true` or a table with options)
* `prompt` (0.19+): Securely ask for a missing value during `secretspec run` and let the selected provider decide whether to save the answer
* `from` (0.22+): Derive a read-only value from another declared secret, either by selecting a field with `extract` or by converting an `x509_identity` into a `pkcs12`, `pkcs8_private_key`, `x509_certificate`, `x509_certificate_chain`, or `x509_issuer_chain` (see the [configuration reference](/reference/configuration/#derived-typed-secrets-022))
* `format` (0.22+): Choose `pem` (default) or `der` for a converted key or certificate
* `credentials` (0.22+): Bind the `password` that opens a stored `x509_identity` or protects a derived `pkcs12` to another declared secret

## Related Concepts

* [Configuration Inheritance](/concepts/inheritance/) lets projects share common secret definitions via the `extends` field
* [Secret Generation](/concepts/generation/) auto-creates passwords, tokens, and keys when secrets are missing
* [Run prompts (0.19+)](/reference/configuration/#prompt-on-missing-during-run-019) provision stored secrets on first use, or remain invocation-only with `null`
* [Composed Secrets (0.16+)](/concepts/composed-secrets/) derive values from other declared secrets without dotenv or shell expansion

## Best Practices

1. **Descriptive names**: Use `STRIPE_API_KEY` instead of generic `API_KEY`
2. **Clear descriptions**: Help developers understand each secret’s purpose
3. **Sensible defaults**: Provide development defaults, require production values
4. **Modular inheritance**: Create reusable base configurations for common patterns

## Complete Example

```toml
[project]
name = "web-api"
revision = "1.0"
extends = ["../shared/base", "../shared/auth"]


[profiles.default]
# Inherits DATABASE_URL, INTERNAL_API_KEY from base
# Inherits JWT_SECRET, SESSION_SECRET from auth
# Service-specific additions:
STRIPE_API_KEY = { description = "Stripe payment API", required = true }
REDIS_URL = { description = "Redis cache connection", required = true }
PORT = { description = "Server port", required = false, default = "3000" }
```