mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Five reports on this page, four of them the same confusion: which .env file does what. Where local values come from is a new section listing the files that feed a local environment: supabase/functions/.env, a file you name yourself, the root .env that config.toml reads through env(), and [edge_runtime.secrets]. It says a value in one is not a value in the other. That is what CLI-818 asked for in as many words, the duplication FDBKIN-11884 complains about, and the config route FDBKIN-12716 raises. It sits with the other reference section rather than inside the local procedure, because it answers what the parts are rather than how to do something. Accessing environment variables splits into an Edge Function and a Deno script you run yourself, where neither env file applies. Deno.env.get needs --allow-env, so both commands pass it; without the flag the script prompts, and fails outright when nothing is there to answer. FDBKIN-7937. Production secrets now states who can set one, and the reserved prefix. Also calls Deno.env.get a method rather than a handler, which is what it is. The wording came in with the style pass at the bottom of the stack; fixing it here avoids restacking four branches for one word. Two claims from the source reports are deliberately not here. FDBKIN-34962 reports that adding a secret requires OWNER. The access control matrix in guides/platform/access-control.mdx says Owner or Administrator can create and delete, and Developer can view. The reporter found their version by external searching, so the page states what our own matrix says. supabase/agent-skills#452 reports that a secret value cannot be recovered after saving. SecretResponse_Output in the Management API spec returns value as a required field, and the Dashboard renders it, so that does not hold up from what I can check here. Left out rather than guessed at; the issue stays open. The reserved prefix is not a third-party host restriction as supabase/agent-skills#553 frames it. CreateSecretBody carries pattern ^(?!SUPABASE_).*, AddNewSecretForm.tsx:42 rejects the same, and the CLI filters SUPABASE_-prefixed names out of the local function environment. It is ours, and the page says so.
224 lines
7.9 KiB
Plaintext
224 lines
7.9 KiB
Plaintext
---
|
|
id: 'functions-secrets'
|
|
title: 'Environment variables'
|
|
description: 'Managing secrets and environment variables.'
|
|
subtitle: 'Manage sensitive data securely across environments.'
|
|
---
|
|
|
|
Store API keys and other secrets where your Edge Functions can read them. Local development and production load them differently, so set them in both.
|
|
|
|
## Local secrets
|
|
|
|
In development, Edge Functions read secrets from `supabase/functions/.env`, which is automatically loaded on `supabase start`. Create the file before you start the stack.
|
|
|
|
1. Create `supabase/functions/.env` and add each secret with the value you want the function to read. A `.env.example` template isn't enough on its own, because the runtime reads the values rather than the variable names.
|
|
|
|
```bash
|
|
# supabase/functions/.env
|
|
STRIPE_SECRET_KEY=sk_test_...
|
|
```
|
|
|
|
2. Add the file to your `.gitignore`, along with every other env file you create. A `.env` file committed to Git exposes every secret in it to anyone who can read the repository.
|
|
|
|
```bash
|
|
# .gitignore
|
|
supabase/functions/.env
|
|
.env.local
|
|
```
|
|
|
|
3. Create the function, then replace its contents to read the secret and report whether it arrived. Return the result of the check rather than the value, so the response never carries the secret.
|
|
|
|
```bash
|
|
supabase functions new hello-world
|
|
```
|
|
|
|
```tsx
|
|
// supabase/functions/hello-world/index.ts
|
|
Deno.serve(() => {
|
|
const secretKey = Deno.env.get('STRIPE_SECRET_KEY')
|
|
return Response.json({ configured: Boolean(secretKey) })
|
|
})
|
|
```
|
|
|
|
4. Start the local stack.
|
|
|
|
```bash
|
|
supabase start
|
|
```
|
|
|
|
5. Call the function. A `configured` of `true` means the runtime handed it the secret.
|
|
|
|
```bash
|
|
curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/hello-world' \
|
|
--header 'apikey: <SUPABASE_PUBLISHABLE_KEY>'
|
|
```
|
|
|
|
Your function now reads the secret from your local environment.
|
|
|
|
---
|
|
|
|
## Accessing environment variables
|
|
|
|
Access an environment variable with the `Deno.env.get` method, passing the name of the variable you want.
|
|
|
|
```js
|
|
Deno.env.get('NAME_OF_SECRET')
|
|
```
|
|
|
|
### In an Edge Function
|
|
|
|
```ts
|
|
import { createClient } from 'npm:@supabase/supabase-js@2'
|
|
|
|
const SUPABASE_PUBLISHABLE_KEYS = JSON.parse(Deno.env.get('SUPABASE_PUBLISHABLE_KEYS')!)
|
|
|
|
// For user-facing operations (respects RLS)
|
|
const supabase = createClient(
|
|
Deno.env.get('SUPABASE_URL')!,
|
|
// To use a different API key, change 'default' to your preferred key name
|
|
SUPABASE_PUBLISHABLE_KEYS['default']
|
|
)
|
|
|
|
const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
|
|
// For admin operations (bypasses RLS)
|
|
const supabaseAdmin = createClient(
|
|
Deno.env.get('SUPABASE_URL')!,
|
|
// To use a different API key, change 'default' to your preferred key name
|
|
SUPABASE_SECRET_KEYS['default']
|
|
)
|
|
```
|
|
|
|
### In a Deno script
|
|
|
|
A Deno script you run yourself, outside `supabase functions serve`, doesn't read `supabase/functions/.env`. Pass the file, and grant the script access to the environment with `--allow-env`:
|
|
|
|
```bash
|
|
deno run --allow-env --env-file=supabase/functions/.env script.ts
|
|
```
|
|
|
|
Or set the variable for a single command:
|
|
|
|
```bash
|
|
STRIPE_SECRET_KEY=sk_test_... deno run --allow-env script.ts
|
|
```
|
|
|
|
---
|
|
|
|
## When your function can't read a secret
|
|
|
|
The local runtime loads `supabase/functions/.env` when the stack starts, so a function that returns nothing for a variable usually means the value never reached it.
|
|
|
|
Restart the stack, or serve the function with the file passed explicitly:
|
|
|
|
```bash
|
|
supabase functions serve hello-world --env-file supabase/functions/.env
|
|
```
|
|
|
|
To keep a separate file per environment, name your own and pass it the same way:
|
|
|
|
```bash
|
|
supabase functions serve --env-file .env.local
|
|
```
|
|
|
|
---
|
|
|
|
## Production secrets
|
|
|
|
Set secrets for your production Edge Functions in the Dashboard or with the CLI.
|
|
|
|
Creating or deleting a production secret requires the Owner or Administrator role. Developers can view secrets but not change them. See [Access control](/docs/guides/platform/access-control#edge-config-permissions) for the full matrix.
|
|
|
|
A secret name can't start with `SUPABASE_`. That prefix is reserved for the variables Supabase injects, and both the Dashboard and the Management API reject it.
|
|
|
|
### Using the Dashboard
|
|
|
|
1. Open [Edge Function Secrets](/dashboard/project/_/functions/secrets) in the Dashboard.
|
|
2. Enter the **Key** and **Value** for your secret, then click **Save**.
|
|
|
|
<Image
|
|
alt="The Edge Function Secrets page in the Supabase Dashboard. An Add new secrets card holds a Key field hinting e.g. CLIENT_KEY and a Value field with a reveal toggle and a remove button, above an Add another button and a Save button."
|
|
src={{
|
|
light: '/docs/img/edge-functions-secrets--light.jpg',
|
|
dark: '/docs/img/edge-functions-secrets.jpg',
|
|
}}
|
|
width={3757}
|
|
height={1525}
|
|
/>
|
|
|
|
You can paste multiple secrets at once.
|
|
|
|
### Using the CLI
|
|
|
|
Create a `.env` file with the secrets you want to deploy. Add it to your `.gitignore` before you commit.
|
|
|
|
```bash
|
|
# .env
|
|
STRIPE_SECRET_KEY=sk_live_...
|
|
```
|
|
|
|
Push every secret in the file to your remote project with `supabase secrets set`, which also makes them visible in the Dashboard.
|
|
|
|
```bash
|
|
supabase secrets set --env-file .env
|
|
```
|
|
|
|
This command also sets production secrets individually, without a `.env` file.
|
|
|
|
```bash
|
|
supabase secrets set STRIPE_SECRET_KEY=sk_live_...
|
|
```
|
|
|
|
To see the secrets you have set remotely, use `supabase secrets list`.
|
|
|
|
```bash
|
|
supabase secrets list
|
|
```
|
|
|
|
<Admonition type="note">
|
|
|
|
Secrets are available in your functions immediately. You don't need to redeploy after setting them.
|
|
|
|
</Admonition>
|
|
|
|
Your deployed functions can now read the secret.
|
|
|
|
---
|
|
|
|
## Where local values come from
|
|
|
|
A project can hold more than one file that feeds local environment variables, and they aren't interchangeable:
|
|
|
|
- `supabase/functions/.env` is the one your Edge Functions read, loaded when the stack starts.
|
|
- A file you name yourself, such as `.env.local`, passed to `supabase functions serve` with `--env-file`.
|
|
- A `.env` at the root of your project is the one `config.toml` reads, through its `env()` function. See [Using secrets inside config.toml](/docs/guides/local-development/managing-config#using-secrets-inside-configtoml). A variable your function needs has to be in `supabase/functions/.env` too, even when the same value is already in the root file.
|
|
|
|
You can also set local values in `config.toml` itself, under `[edge_runtime.secrets]`:
|
|
|
|
```toml
|
|
[edge_runtime.secrets]
|
|
STRIPE_SECRET_KEY = "env(STRIPE_SECRET_KEY)"
|
|
```
|
|
|
|
---
|
|
|
|
## Default secrets
|
|
|
|
Alongside the secrets you set yourself, Edge Functions have access to these by default:
|
|
|
|
- `SUPABASE_URL`: The API gateway for your Supabase project
|
|
- `SUPABASE_DB_URL`: The URL for your Postgres database. Use it to connect directly to your database
|
|
- `SUPABASE_PUBLISHABLE_KEYS`: The `publishable` keys JSON dictionary for your Supabase API. This is safe to use in a browser when you have Row Level Security enabled
|
|
- `SUPABASE_SECRET_KEYS`: The `secret` keys JSON dictionary for your Supabase API. This is safe to use in Edge Functions, but **never** use it in a browser. These keys bypass Row Level Security
|
|
- `SUPABASE_JWKS`: The JSON Web Key Set used to verify user JWTs. Same value served at `https://<project-ref>.supabase.co/auth/v1/.well-known/jwks.json`
|
|
|
|
Legacy keys:
|
|
|
|
- `SUPABASE_ANON_KEY`: The `anon` key for your Supabase API. This is safe to use in a browser when you have Row Level Security enabled
|
|
- `SUPABASE_SERVICE_ROLE_KEY`: The `service_role` key for your Supabase API. This is safe to use in Edge Functions, but **never** use it in a browser. This key bypasses Row Level Security
|
|
|
|
In a hosted environment, functions have access to the following environment variables:
|
|
|
|
- `SB_REGION`: The region the function was invoked in
|
|
- `SB_EXECUTION_ID`: A UUID for the function instance, or [isolate](/docs/guides/functions/architecture#4-execution-mechanics-fast-and-isolated)
|
|
- `DENO_DEPLOYMENT_ID`: The version of the function code, formatted as `{project_ref}_{function_id}_{version}`
|