docs(functions): give local secrets a procedure that produces a working key (#50420)

The Managing secrets guide is the only place that tells you where a local
secret has to sit for the Edge Function runtime to load it. Neither the
supabase agent skill nor Supacademy covers it.

The page named supabase/functions/.env once, in prose, and never had the reader
create it. The eval in supabase/evals#285 reproduces what that produces: across
three runs on codex-gpt-5.6-luna-no-skills, every run built a function reading
its key from the environment, started the stack, and answered missing_api_key.
Two of the three wrote supabase/functions/.env.example and stopped, which is a
template with the variable name in it rather than the file the runtime reads.

Local secrets is now a five-step procedure that creates the file with a working
value, ignores it, creates the function that reads the key, starts the stack,
and calls the function to confirm. That last step is the one that tells the
reader whether it worked. The function is created before the stack starts, so a
reader following the steps literally from a fresh project has something to call.

The gitignore instruction moved out of its admonition and into step 2, carrying
its consequence with it. It's an instruction the reader has to follow, so it
belongs in the procedure rather than beside it.

Recovery for a variable the function can't see gets its own section rather than
trailing the procedure. "I set it and the function cannot read it" is the most
repeated shape in the feedback on this page, and as loose sentences mid-section
it had no entry in the table of contents.
This commit is contained in:
Miranda Limonczenko authored and GitHub committed 2026-09-18 16:02:48 -07:00
1 parent 7012ba4a55
commit 06aafbae4b
1 file changed
+57 -11
+57 -11
View File
@@ -9,23 +9,51 @@ Store API keys and other secrets where your Edge Functions can read them. Local
## Local secrets
In development, Edge Functions read secrets from `supabase/functions/.env`, which is automatically loaded on `supabase start`. To use a file you name yourself, such as `.env.local`, pass it to `supabase functions serve` with the `--env-file` option.
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.
```bash
supabase functions serve --env-file .env.local
```
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.
<Admonition type="caution">
```bash
# supabase/functions/.env
STRIPE_SECRET_KEY=sk_test_...
```
A `.env` file committed to Git exposes every secret in it to anyone who can read the repository. Add the file to your `.gitignore` before you commit.
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.
</Admonition>
```bash
# .gitignore
supabase/functions/.env
.env.local
```
Serve the function locally:
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 serve hello-world
```
```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.
---
@@ -62,6 +90,24 @@ const supabaseAdmin = createClient(
---
## 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.