# Environment variables and secrets

> The environment variables SupaHost gives every Edge Function, how to add your own secrets in the Functions tab, naming rules and limits, and how to read them in code.

Source: https://supahost.app/docs/functions/secrets · Updated 2026-11-11

Functions often need values that must stay out of your source code: an email API key, a Stripe secret, a webhook signing secret. On SupaHost you store these as **secrets** on the project. Every function in the project can read them as environment variables with `Deno.env.get`.

## Variables you get automatically

| Variable | Value |
|---|---|
| `SUPABASE_URL` | The project's API URL, for example `https://app-one.acme.supahost.space`. If the project has an active custom domain, this is the custom domain. |
| `SUPABASE_ANON_KEY` | The project's public `anon` key. |
| `SUPABASE_SERVICE_ROLE_KEY` | The project's `service_role` key. It bypasses Row Level Security, so keep it inside functions. |
| `SUPABASE_FUNCTION_SLUG` | The name of the function that's running. |

There is no `SUPABASE_DB_URL`. Functions talk to the database through the Data API with supabase-js; see [Using the database from a function](/docs/functions/database-access).

## Add a secret

*Dashboard → your project → **Functions** tab → **Secrets** card*:

1. Type the name, for example `RESEND_API_KEY`.
2. Paste the value.
3. Click **Add secret**.

To change a value, enter the same name with the new value; the button reads **Update**. To delete one, click **Remove** next to its name. Only the project owner can add, update or remove secrets.

Values are stored encrypted in Vault and never shown again, not even to the owner. The card lists only the names. Changes reach running functions within about a minute, and you don't need to redeploy.

## Rules and limits

| Rule | Value |
|---|---|
| Name format | Letters, numbers and `_`, not starting with a number, up to 100 characters (`^[A-Za-z_][A-Za-z0-9_]{0,99}$`). Upper snake case is the convention. |
| Reserved prefix | Names starting with `SUPABASE_` are reserved for the built-in variables. |
| Number of secrets | Up to 100 per project. |
| Value size | Up to 10,000 characters. |

Secrets are per project, shared by all of that project's functions. They aren't copied to branches, so add them again on a branch that runs functions.

## Read a secret in code

```ts
const RESEND_API_KEY = Deno.env.get("RESEND_API_KEY");
if (!RESEND_API_KEY) {
  // Fail loudly at boot instead of sending a confusing request later.
  throw new Error("RESEND_API_KEY isn't set. Add it in the Functions tab's Secrets card.");
}

Deno.serve(async (req) => {
  const { to, subject, html } = await req.json();
  const res = await fetch("https://api.resend.com/emails", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${RESEND_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ from: "Invoices <billing@mail.example.com>", to: [to], subject, html }),
  });
  return new Response(await res.text(), { status: res.status });
});
```

(That snippet sends whatever the caller asks for, which is fine for a sketch. A real function should check who the caller is and build the email itself; see [Example: sending email](/docs/functions/sending-email).)

A missing secret thrown at boot shows up as a `503 BOOT_ERROR` for callers and a boot error in the function's logs, which is easy to spot.

## Keep secrets out of responses and logs

- Don't return secrets in responses, even in error messages.
- Don't `console.log` request headers or environment variables wholesale. Logs are visible to every member of the team.
- Never send `SUPABASE_SERVICE_ROLE_KEY` back to a browser. If client code needs a key, it's the anon key.

To check which secret names a function can see without printing values, see [Inspecting function environment variables](/kb/function-env-vars).

## Local development

When you run functions locally with the Supabase CLI (`supabase functions serve`), put the same names in a local env file and pass it with `--env-file`. Keep that file out of git. The local values never reach SupaHost; add them in the Secrets card for the deployed project.

```bash
# supabase/functions/.env.local  (gitignored)
RESEND_API_KEY=re_test_xxxxxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxx
```

```bash
supabase functions serve --env-file supabase/functions/.env.local
```

## Secrets in the database instead

Values that SQL needs, such as a key for a cron job that calls a function, belong in the database's Vault rather than in function secrets. See [Storing secrets with Vault](/docs/database/vault) and [Running functions on a schedule](/docs/functions/scheduling).

## Related

- [Keeping keys safe](/docs/security/api-key-safety)
- [API keys](/docs/api/api-keys)
- [Writing functions: Deno, imports and structure](/docs/functions/writing-functions)
