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:

index.ts
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.

Secrets

Add secrets in the Functions section. Every function on the project can read them as environment variables:

index.ts
const apiKey = Deno.env.get('STRIPE_SECRET_KEY')
if (!apiKey) return new Response('Missing secret', { status: 500 })

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:

index.ts
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

app.ts
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:

index.ts
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 })
})