Supabase Edge Functions: Server-Side Logic Without a Server
You need server-side logic — webhook processing, third-party API calls, or data transformations — but you do not want to set up and maintain a backend server. Supabase Edge Functions give you serverless compute that runs close to your database.
What Edge Functions Are
Edge Functions are Deno-based serverless functions deployed to Supabase infrastructure. They run on the edge (close to users) and have direct access to your Supabase project.
Key characteristics:
- Written in TypeScript or JavaScript
- Run on Deno runtime
- Cold starts under 200ms
- Direct access to Supabase client libraries
- Triggered via HTTP, database webhooks, or cron
Basic Function
// supabase/functions/hello-world/index.ts
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
serve(async (req) => {
const { name } = await req.json();
return new Response(
JSON.stringify({ message: `Hello, ${name}!` }),
{ headers: { "Content-Type": "application/json" } },
);
});
Deploy:
supabase functions deploy hello-world
Invoke:
curl -X POST https://your-project.supabase.co/functions/v1/hello-world \
-H "Authorization: Bearer YOUR_ANON_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "World"}'
Real Use Case: Webhook Processing
Process Stripe webhooks with payment verification:
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";
import Stripe from "https://esm.sh/stripe@14";
const stripe = new Stripe(Deno.env.get("STRIPE_SECRET_KEY")!, {
apiVersion: "2024-04-10",
});
serve(async (req) => {
const signature = req.headers.get("stripe-signature")!;
const body = await req.text();
const event = stripe.webhooks.constructEvent(
body,
signature,
Deno.env.get("STRIPE_WEBHOOK_SECRET")!,
);
const supabase = createClient(
Deno.env.get("SUPABASE_URL")!,
Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!,
);
switch (event.type) {
case "checkout.session.completed": {
const session = event.data.object;
await supabase
.from("subscriptions")
.upsert({
user_id: session.metadata?.user_id,
status: "active",
stripe_customer_id: session.customer,
current_period_end: new Date(session.expires_at! * 1000).toISOString(),
});
break;
}
case "customer.subscription.deleted": {
const subscription = event.data.object;
await supabase
.from("subscriptions")
.update({ status: "canceled" })
.eq("stripe_customer_id", subscription.customer);
break;
}
}
return new Response(JSON.stringify({ received: true }), { status: 200 });
});
Database Webhooks
Trigger a function when data changes:
-- In Supabase Dashboard → Database → Webhooks
-- Or via SQL:
CREATE TRIGGER on_new_user
AFTER INSERT ON auth.users
FOR EACH ROW
EXECUTE FUNCTION supabase_functions.http_request(
'https://your-project.supabase.co/functions/v1/on-new-user'