Secrets and config
Parameterize sensitive and environment-specific values without hardcoding them.
Secrets and config let you parameterize values that services need, instead of hardcoding them in specific.hcl:
- Secrets - sensitive information that should never be committed to version control: API keys, database passwords, signing keys.
- Config - non-sensitive values that may vary between environments: log levels, feature flags, URLs.
Because every value is declared in specific.hcl, Specific knows exactly which ones are missing and prompts you for them when needed, both when starting specific dev and when deploying to the cloud. There’s no .env file to assemble by hand.
Secrets
Declare the secrets your application needs and reference them in env:
secret "stripe_api_key" {}
secret "jwt_secret" {
generated = true
}
service "api" {
build = build.api
command = "./api"
endpoint {
public = true
}
env = {
STRIPE_API_KEY = secret.stripe_api_key
JWT_SECRET = secret.jwt_secret
}
}
Secret fields:
generated- whentrue, auto-generates a random string if no value is set. Useful for internal secrets like JWT signing keys.length- length of generated secrets (default: 64). Only applies whengenerated = true.
Manual secrets (no generated flag) must be given a value: locally in specific.local, in production during deployment. Generated secrets are auto-created on first run, and you can still override them manually.
Config
config "log_level" {
default = "info"
}
service "api" {
build = build.api
command = "./api"
endpoint {
public = true
}
env = {
LOG_LEVEL = config.log_level
}
}
Config fields:
default- value used unless overridden by an environment or locally.
Environment overrides
Override config values per environment with environment blocks:
config "log_level" {
default = "info"
}
environment "production" {
config = {
log_level = "warn"
}
}
environment "staging" {
config = {
log_level = "debug"
}
}
Local development: specific.local
Local secret and config values live in specific.local, a gitignored HCL file next to specific.hcl:
secrets {
stripe_api_key = "sk_test_..."
}
config {
log_level = "debug"
}
You don’t have to fill it out ahead of time: specific dev prompts for any missing secrets and config values on startup. The file is never included in deployments.
Production
During specific deploy, the CLI checks that every required value is set for the target environment and prompts you interactively for anything missing. You can enter values while builds are still running. Values can also be passed as flags: specific deploy --secret stripe_api_key=sk_live_....
- Secrets are stored securely, never logged, and injected into services as environment variables at runtime.
- Secrets are scoped per environment - setting a secret for
stagingdoes not affectproduction. - Update secrets and config anytime from the dashboard, without touching
specific.hcl. New values take effect on the next deployment.
Preview environments
Preview environments inherit their secrets and config values from the environment they branch from, so a preview starts with the parent’s configuration without re-entering anything.
To give previews a different value for a specific secret or config, set a preview override on the parent environment’s Secrets and config page in the dashboard. Every preview branched from that environment then uses the override for that value while still inheriting the rest - handy for pointing previews at a sandbox API key or a test-only endpoint. See Preview environments.
Complete example
# External API key: must be set manually, sensitive
secret "stripe_api_key" {}
# Internal signing key: auto-generated, sensitive
secret "jwt_secret" {
generated = true
}
# Log level: not sensitive, varies by environment
config "log_level" {
default = "info"
}
service "api" {
build = build.api
command = "./api"
endpoint {
public = true
}
env = {
STRIPE_API_KEY = secret.stripe_api_key
JWT_SECRET = secret.jwt_secret
LOG_LEVEL = config.log_level
}
}
environment "production" {
config = {
log_level = "warn"
}
}