Supabase Edge Functions Guide
Edge Functions are server-side TypeScript functions that run on Deno Deploy, distributed globally at the edge.
Project Structure
supabase/
functions/
my-function/
index.ts # Entry point (required)
shared/
cors.ts # Shared utilities
types.ts
Each function lives in its own directory under supabase/functions/ .
Basic Function
import { serve } from "https://deno.land/std@0.177.0/http/server.ts" ;
serve ( async ( req : Request ) => {
const { name } = await req. json ();
return new Response (
JSON . stringify ({ message: `Hello, ${ name }!` }),
{ headers: { "Content-Type" : "application/json" } }
);
});
CORS Handling
Create a shared CORS utility:
// supabase/functions/shared/cors.ts
export const corsHeaders = {
"Access-Control-Allow-Origin" : "*" ,
"Access-Control-Allow-Headers" : "authorization, x-client-info, apikey, content-type" ,
};
Use in your function:
import { corsHeaders } from "../shared/cors.ts" ;
serve ( async ( req : Request ) => {
// Handle CORS preflight
if (req.method === "OPTIONS" ) {
return new Response ( "ok" , { headers: corsHeaders });
}
// Your logic here
return new Response (
JSON . stringify ({ data: "result" }),
{ headers: { ... corsHeaders, "Content-Type" : "application/json" } }
);
});
Environment Variables
Set secrets via CLI:
supabase secrets set MY_API_KEY=sk-xxx
supabase secrets list
Access in code:
const apiKey = Deno.env. get ( "MY_API_KEY" );
Built-in variables (always available):
SUPABASE_URL
SUPABASE_ANON_KEY
SUPABASE_SERVICE_ROLE_KEY
SUPABASE_DB_URL
Invoking from Client
const { data , error } = await supabase.functions. invoke ( "my-function" , {
body: { name: "World" },
});
The client automatically sends the user's auth token in the Authorization header.
Error Handling
serve ( async ( req : Request ) => {
try {
const body = await req. json ();
if ( ! body.email) {
return new Response (
JSON . stringify ({ error: "email is required" }),
{ status: 400 , headers: { "Content-Type" : "application/json" } }
);
}
// process...
return new Response ( JSON . stringify ({ success: true }), {
headers: { "Content-Type" : "application/json" },
});
} catch (err) {
return new Response (
JSON . stringify ({ error: "Internal server error" }),
{ status: 500 , headers: { "Content-Type" : "application/json" } }
);
}
});
Deploying
# Deploy a single function
supabase functions deploy my-function
# Deploy all functions
supabase functions deploy
# Local development
supabase functions serve my-function --env-file .env.local
Testing Locally
curl -i --location --request POST \
http://localhost:54321/functions/v1/my-function \
--header 'Authorization: Bearer YOUR_ANON_KEY' \
--header 'Content-Type: application/json' \
--data '{"name": "World"}'