Skip to main content
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:
specific.hcl
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 - when true, 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 when generated = 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.
Secret and config references cannot be interpolated into strings; use them as standalone env values.

Config

specific.hcl
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:
specific.hcl
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:
specific.local
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 staging does not affect production.
  • Update secrets and config anytime from the dashboard, without touching specific.hcl. New values take effect on the next deployment.

Complete example

specific.hcl
# 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"
  }
}