Skip to main content

Secrets done right

Beginner ⏱ 8 min secrets · config · production

You will build: an app whose config contains zero credentials — and a deploy that fails loudly if a secret is missing, instead of shipping a broken pipeline.

${secret:NAME} → resolved at deploy

Prerequisites

  • Any app with a sink or credentialed connector.

1 · Store a secret locally

pulse secret set ALERT_WEBHOOK https://hooks.example.com/T000/B000/xxxx

Stored in the CLI's local secret store (file mode 0600). List and remove with pulse secret list · pulse secret rm NAME.

2 · Reference it — never paste it

sink:
kind: webhook
url: ${secret:ALERT_WEBHOOK}

Two reference forms exist: ${secret:NAME} (CLI secret store) and ${env:VAR} (environment variable). The scaffolder already emits these for credential fields — follow its lead.

3 · See the guard in action

pulse secret rm ALERT_WEBHOOK
pulse deploy .

Deploy aborts with a named error: the reference ${secret:ALERT_WEBHOOK} cannot be resolved. A config with a hole in it never reaches the runtime.

4 · Restore and deploy clean

pulse secret set ALERT_WEBHOOK https://hooks.example.com/T000/B000/xxxx
pulse deploy .

What just happened

Secrets are resolved at deploy time, from outside the file. The YAML you commit to git carries references, never values — so the same file is safe in a PR, and the same app deploys against dev or prod credentials by changing what the references resolve to, not the file itself.

Troubleshooting

Where does the secret store live?

pulse secret path shows you. It's a local file with owner-only permissions (0600) — per developer, per machine.

Next