Docs · Functions
Edge functions
Edge functions are Deno handlers that run on your project’s server. Use them for webhooks, calls to third-party APIs and anything that needs a secret.
Write a function
In your project, open Functions and create a new function. Each function starts with an index.ts file:
Deno.serve(async (req) => {
const { name } = await req.json().catch(() => ({ name: 'world' }))
return new Response(JSON.stringify({ message: `Hello ${name}!` }), {
headers: { 'Content-Type': 'application/json' },
})
})Deploy it from the editor. It’s served at /functions/v1/<name> on your project URL.
- Names use lowercase letters, digits,
-and_. The namesmainandavoca-secretsare reserved. - Require a valid JWT is on by default: callers must send the anon key or a signed-in user’s token. Turn it off for public webhooks, and check the request yourself (for example, verify a webhook signature).
Secrets
Add secrets in the Functions section. Every function on the project can read them as environment variables:
const apiKey = Deno.env.get('STRIPE_SECRET_KEY')
if (!apiKey) return new Response('Missing secret', { status: 500 })- Names use
A–Z,0–9and_, and can’t start with a digit. - Names starting with
SUPABASE_are reserved and can’t be set. - Values are write-only: once saved they can’t be read back in the dashboard. To change one, set it again.
Use the database from a function
To read or write data with full access from a function, store your project URL and service key as secrets (with names that don’t start with SUPABASE_) and create a client inside the function:
import { createClient } from 'npm:@supabase/supabase-js@2'
const admin = createClient(
Deno.env.get('PROJECT_URL')!,
Deno.env.get('SERVICE_KEY')!
)
Deno.serve(async () => {
const { count } = await admin
.from('todos').select('*', { count: 'exact', head: true })
return Response.json({ count })
})The service key bypasses Row Level Security. Keep it in secrets, never in frontend code, and check who is calling before you use it.
Call a function
const { data, error } = await supabase.functions.invoke('hello', {
body: { name: 'Da8a' }
})supabase.functions.invoke sends the signed-in user’s token (or the anon key), so it works with Require a valid JWT turned on. From other tools, send an Authorization: Bearer <token> header.
Calling from a browser on another domain
If your site calls the function directly with fetch from a different origin, answer the preflight request and add CORS headers:
const cors = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, content-type, apikey',
}
Deno.serve(async (req) => {
if (req.method === 'OPTIONS') return new Response('ok', { headers: cors })
return Response.json({ ok: true }, { headers: cors })
})