Skip to content

Writing and Invoking a Function

An Edge Function is a plain Deno.serve handler that receives an HTTP request and returns a response, invoked from a client with supabase.functions.invoke().

Deno.serve is a global provided by the Deno runtime — there is nothing to import for it. You hand it a callback that receives the incoming Request and returns a Response, exactly like the Fetch API you already know from the browser:

Deno.serve(async (req) => {
const { name } = await req.json()
return new Response(JSON.stringify({ message: `Hello ${name}!` }), {
headers: { 'Content-Type': 'application/json' },
})
})

This file lives at supabase/functions/hello-world/index.ts. Once deployed, it is reachable at https://<project-ref>.supabase.co/functions/v1/hello-world, but you rarely construct that URL by hand — the client library does it for you.

supabase-js exposes a dedicated functions.invoke() method rather than a plain fetch, because it does useful work on your behalf:

const { data, error } = await supabase.functions.invoke('hello-world', {
body: { name: 'World' },
})

Beyond serializing body to JSON, invoke() automatically attaches an Authorization header — the currently signed-in user’s access token if someone is logged in, or the project’s anon key otherwise. That means your function can inspect who called it (or confirm no one is authenticated) without you wiring that header manually on every call.

A function frequently needs a credential it should never expose to the client — a third-party API key, a signing secret. Set one for your deployed functions with the CLI:

Terminal window
supabase secrets set MY_API_KEY=sk_live_examplekey123

Read it inside the function with Deno.env.get:

const apiKey = Deno.env.get('MY_API_KEY')

For local development, supabase functions serve reads a .env file placed under supabase/functions/, so the same Deno.env.get call works identically whether you are running locally or against the deployed function — only where the value comes from changes.

flowchart LR
  client["supabase.functions.invoke('hello-world', { body })"] -->|"HTTP request + Authorization header"| edge["Deployed Deno function (Deno.serve)"]
  edge -->|"Response"| client
A client invocation reaching a deployed Deno function
Do you need to import anything to use Deno.serve in an Edge Function
What does supabase.functions.invoke() automatically attach to the request
How do you set a secret for a deployed Edge Function
How does local development read environment variables for a function