---
title: "How do I use secrets and env vars in steps?"
description: "TL;DR: Store every credential in Secrets, then reference it with ${VAR} in connector headers and HTTP steps, or read it from the environment in Code steps. Secrets are encrypted per workspace and resolved at run time, so keys never live in playbook bodies, source control, or run output."
canonical_url: "https://docs.ballet.dev/articles/how-do-i-use-secrets-and-env-vars-in-steps-7AeJ7El3L1"
md_url: "https://docs.ballet.dev/articles/how-do-i-use-secrets-and-env-vars-in-steps-7AeJ7El3L1.md"
---
# How do I use secrets and env vars in steps?

**TL;DR:** Store every credential in Secrets, then reference it with `${VAR}` in connector headers and HTTP steps, or read it from the environment in Code steps. Secrets are encrypted per workspace and resolved at run time, so keys never live in playbook bodies, source control, or run output.

## Who this is for

Developers handling API keys, tokens, and other credentials inside playbooks.

## Where do secrets live?

Secrets are stored in Ballet's per-tenant encrypted store. You add them once and reference them by name wherever a credential is needed — they are never written into the playbook definition.

## How do I reference a secret?

- **Connector headers and HTTP steps** — use `${VAR}` interpolation:

```http
Authorization: Bearer ${EXAMPLE_API_KEY}
```

- **Code steps** — read from the environment:

```ts
const key = process.env.EXAMPLE_API_KEY;
```

The placeholders are resolved at connect/run time from the workspace secret store.

## How is this different from an API token?

| | Secret | API token |
|---|---|---|
| Purpose | Credentials a playbook uses to call *out* to other systems | A credential others use to call *into* Ballet |
| Where used | Steps, connector headers | `Authorization: Bearer` on Ballet API/MCP requests |
| Managed in | Secrets | Settings → API tokens |

See [authentication](/articles/how-do-i-authenticate-with-the-ballet-api-tWaqCPLyGT) for API tokens.

## Best practices

- One secret per credential; give it a clear, specific name.
- Never paste keys directly into a step, prompt, or commit.
- Rotate by updating the secret value — references keep working.
- Return only non-sensitive data from steps so secrets don't leak into run output.

## Related articles

- [How do I store credentials with Secrets?](/articles/how-do-i-store-credentials-with-secrets-1D8OUcCo0n)
- [How do playbooks connect to external systems?](/articles/how-do-playbooks-connect-to-external-systems-Jije3yYddT)
- [How do I call external APIs and SDKs from a playbook?](/articles/how-do-i-call-external-apis-and-sdks-from-a-playbook-zX7zFTnqwC)
- [How do I authenticate with the Ballet API?](/articles/how-do-i-authenticate-with-the-ballet-api-tWaqCPLyGT)
