App env vars
Declare the keys your app reads, set the values in the dashboard, read them with your language's standard env-var API at runtime. No SDK required.
The two-line model
Every app follows the same three steps:
Declare keys in your repo's
.env.examplefile. This is the Leash convention regardless of language — we scan this one file to know which keys to inject. Commit it; placeholder values are fine — only the key names are read..env.exampleSTRIPE_SECRET_KEY=OPENAI_API_KEY=Set values in the dashboard at
/dashboard/apps/<id>/secrets. Values are encrypted at rest and injected into your Cloud Run revision at deploy time.Read them in your app code using your language's standard env-var API:
const stripeKey = process.env.STRIPE_SECRET_KEY
Where values can come from
Step 2 — “set values” — has three flavors. Pick whichever matches how your org already stores secrets.
Dashboard direct entry
Paste values directly in the app's Secrets tab. Available on every plan. Best for small teams that don't already run a secrets manager.
SaaS token sources
Connect an existing secrets manager and Leash will resolve values from it on each deploy. Supported today:
- Doppler
- Infisical
- 1Password
- Bitwarden
Configure once at /dashboard/organization/secrets; every app in the org can resolve from it.
Cloud-native federation
Federate directly to your cloud provider's secret store — no values ever leave your account. Coming soon:
- AWS Secrets Manager
- GCP Secret Manager
- Azure Key Vault
Upgrade path
The model above is deploy-time: values are baked into the container when you ship. If you need any of:
- Rotate a key without redeploying
- An audit trail of who read which value when
- Central, immediate revocation
Move those keys to the SDK's dynamic env namespace. See Dynamic env vars — same key names, fetched on demand through @leash/sdk.
Related
- Dynamic env vars — when you need rotation without redeploy, audit trail per read, or central revocation.
- Secret sources — connect Doppler, Infisical, 1Password, or Bitwarden as a backing store for org-wide secrets.
- Rotation gotcha: values read via your language's standard env-var API are injected at container start. Rotating a dashboard secret only takes effect on the next deploy — for instant rotation, use
leash.env.get. - Local dev — pull the same values into your local environment for development with
leash dev.
Encryption
Values are encrypted at rest in GCP Secret Manager under a Cloud KMS CMEK key. By default the key is held by Leash. Org owners can bring their own KMS key via the wizard at /dashboard/organization/security/encryption/cmek — paste a key resource name, Leash runs an encrypt+decrypt round-trip to validate the binding, and from that point on all new writes use your key. Revert to Leash-held at any time.
Audit log
Every source create/edit/revoke, every required-keys update, and every resolved-values pull writes a row at /dashboard/organization/security/audit. Owners can scan the log for anything unusual.
How rotation behaves
Rotating a value in your source updates Leash immediately, but when running app code sees the new value depends on how it reads the secret:
| Read mechanism | Rotation behavior |
|---|---|
process.env.X | Bake-time. The value is mounted into the Cloud Run revision at deploy. Re-deploy (or hit “sync now”) to pick up a new value. |
await leash.env.get('X') | Runtime fetch. The next call after rotation gets the new value (per-instance cache, ~60s); { fresh: true } bypasses the cache. |
| Custom MCP bearer | Per-call resolve. The token is fetched fresh via getCustomMcpConfig on every call — picks up the new value on the next call. |