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.

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.

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

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 <[email protected]>", 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.)

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.

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.

# supabase/functions/.env.local  (gitignored)
RESEND_API_KEY=re_test_xxxxxxxx
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxx
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 and Running functions on a schedule.

Updated 11 November 2026 · View as Markdown · Something wrong or missing? Tell us