> ## Documentation Index
> Fetch the complete documentation index at: https://sdk.docs.xano.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Environment variables and secrets

> Declare workspace environment variable names in code, keep their values in xano/.env, change a value on a running backend with env set, and gate hosted API docs with a token.

A workspace environment variable lives in the backend, and your stack reads it at request time
with `env("NAME")`. You declare the **names** in code. The **values** stay out of git.

## Declare the names

```ts theme={null}
// xano/workspace.ts
import { workspaceConfig, typedEnv, s, c } from "@xano/sdk";

export const wsConfig = workspaceConfig({
  env: {
    STRIPE_KEY: "", // a secret: the value lives in xano/.env
    APP_BASE_URL: "https://my-app.example.com", // a plain config value can live here
  },
});

// Typed accessors: E.STRIPE_KEY autocompletes, E.STRIP_KEY is a compile error.
const E = typedEnv(wsConfig);

// In a stack:
s.api.request({
  url: c.text("https://api.stripe.com/v1/charges"),
  headers: { Authorization: E.STRIPE_KEY },
});
```

Register the config with `.registerWorkspace(wsConfig)`. Leave out `name`: the config inherits
the one `workspace("…")` gives, and naming it here renames the workspace.

Declare every name your stack reads. A name that does not exist reads as `null` rather than
failing, and the export warns about any `env()` outside the declared set.

## Keep the values in xano/.env

| File | Holds | In git |
| - | - | - |
| `xano/.env` | the values, `NAME=value` per line | No, gitignored |
| `xano/.env.example` | the declared names, generated | Yes, commit it |

```bash theme={null}
# xano/.env
STRIPE_KEY=sk_test_REPLACE_ME
```

`deploy`, `export` and `preflight` read `xano/.env` with no flag. On a fresh clone, copy
`xano/.env.example` to `xano/.env` and fill it in, or fetch the values from a running backend:

```bash theme={null}
npx xanosdk env pull                     # from the backend this project last deployed to
npx xanosdk env pull --from tenant:prod  # from a named one
```

`env pull` overwrites `xano/.env`, so it confirms first and names the source.

## A deploy refuses a missing value

A deploy that replaces a backend (the default for an ephemeral) **replaces its env set** with
what you send. A declared name that no file and no flag supplies would clear the live value, so
the deploy refuses and names the variable. To clear one on purpose:

```bash theme={null}
npx xanosdk deploy ./xano/index.ts --ephemeral --allow-empty-env=STRIPE_KEY
```

In CI, where there is no `xano/.env`, pass a file or one value:

```bash theme={null}
npx xanosdk deploy ./xano/index.ts --ephemeral --backend-env-file ci.env  # replaces xano/.env
npx xanosdk deploy ./xano/index.ts --ephemeral --env-var STRIPE_KEY=sk_test_REPLACE_ME
```

## Change a value on a running backend

`env set` creates or replaces one variable, and `env unset` removes one. Nothing is deployed and
every other variable stays as it is:

```bash theme={null}
printf %s "$STRIPE_KEY" | npx xanosdk env set STRIPE_KEY --to workspace --yes  # value on stdin
npx xanosdk env set FEATURE_FLAG on --to local                                   # the Xano Engine
npx xanosdk env unset STRIPE_KEY --to tenant:prod
```

With no `--to`, both write to the ephemeral or Xano Engine this project last deployed to, never
to your workspace or a tenant. A write to the workspace or a tenant asks first; `--yes` skips
the question and is required when the value is piped in. Pipe secrets on stdin to keep them out
of shell history.

Neither command touches `xano/.env`. Update it too if the next deploy should send the new value.

## Rotate a secret with env set, not a deploy

How a backend's env set changes depends on how code reaches it:

| How code arrives | What happens to env |
| - | - |
| A deploy to an ephemeral | The env set is **replaced** with what the deploy sends. |
| `npm run xano:deploy` to the Xano Engine (`--keep-data`) | Merged: only names the Engine does not hold yet are added. |
| `promote` or `tenant deploy` of a release, and every merge | **Add only.** A name the target already holds keeps the target's value. |
| `deploy --to workspace --replace` | Replaced, and every name your config does not declare is dropped. |

So a release never overwrites production's values, and promoting it again does not rotate
anything. To change a value on the workspace or a tenant, set it there:

```bash theme={null}
printf %s "$NEW_STRIPE_KEY" | npx xanosdk env set STRIPE_KEY --to workspace --yes
printf %s "$NEW_STRIPE_KEY" | npx xanosdk env set STRIPE_KEY --to tenant:prod --yes
```

A release carries no env values, and `promote` and `tenant deploy` do not create a newly
declared name on the target. Both commands list every name the release reads that the target
lacks, with the `env set` command that sets it, before they ask to confirm.

## Documentation tokens

The token that gates a hosted API documentation site is a secret too, but it is not an env
var. Declare only the gate in code:

```ts theme={null}
workspaceConfig({ documentation: { require_token: true } });
apiGroup({ name: "Public API", swagger: true, documentation: { require_token: true } });
```

The token lives in `xano/.secrets.json`, gitignored, beside `xano/.env`. `xanosdk pull` writes
it for a gate that already has one. For a gate you just declared, mint one:

```bash theme={null}
npx xanosdk secrets fill   # one token per declared gate that has none; never replaces one
```

A minted token gates nothing until a deploy sends it. CI passes `--secrets-file <path>`.

<Note>
  `deploy --static-env KEY=VALUE` is a different thing: it bakes **public** config into the HTML
  a browser downloads. Never put a secret there.
</Note>

## Next

* Every flag, the `--bundle` caveat, and the CLI's own environment variables:
  [environment variables reference](/reference/environment-variables).
* How env moves between environments when you ship: [Promote and go live](/ship/promote-and-go-live).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.