Supabase Edge Functions are Deno-based serverless functions that run at the edge — close to your users, with access to your Supabase database and auth context. They're the answer to 'I need a bit of server-side logic but I don't want to run a separate backend service.'

When to Use Edge Functions

  • Sending transactional emails triggered by database events
  • Processing webhooks from Stripe, GitHub, or other services
  • Running server-side AI logic that needs access to your database
  • Custom auth logic beyond what Supabase Auth provides natively
  • Calling third-party APIs with secrets that can't be exposed client-side

Creating Your First Edge Function

# Install Supabase CLI
npm install -g supabase
 
# Initialise (if not already done)
supabase init
 
# Create a new edge function
supabase functions new process-document
 
# This creates: supabase/functions/process-document/index.ts
// supabase/functions/process-document/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
 
serve(async (req) => {
  const { document_id, content } = await req.json();
 
  // Access Supabase with service role key (available as env var)
  const supabase = createClient(
    Deno.env.get('SUPABASE_URL')!,
    Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
  );
 
  // Call OpenAI
  const embeddingRes = await fetch('https://api.openai.com/v1/embeddings', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${Deno.env.get('OPENAI_API_KEY')}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ model: 'text-embedding-3-small', input: content }),
  });
  const { data } = await embeddingRes.json();
  const embedding = data[0].embedding;
 
  // Save to database
  await supabase
    .from('documents')
    .update({ embedding })
    .eq('id', document_id);
 
  return new Response(JSON.stringify({ success: true }), {
    headers: { 'Content-Type': 'application/json' },
  });
});

Setting Secrets

# Set secrets for your edge functions
supabase secrets set OPENAI_API_KEY=sk-...
 
# List current secrets
supabase secrets list

Deploying

# Deploy a specific function
supabase functions deploy process-document
 
# Deploy all functions
supabase functions deploy
 
# The function URL is:
# https://[project-ref].supabase.co/functions/v1/process-document

Calling Edge Functions from Your App

// From a Next.js server component or API route
const { data, error } = await supabase.functions.invoke('process-document', {
  body: { document_id: '123', content: 'text to embed...' },
});
 
// The Supabase client automatically sends the user's JWT
// so your function can verify authentication

Recipe: Stripe Webhook Handler

// supabase/functions/stripe-webhook/index.ts
import Stripe from 'https://esm.sh/stripe@13';
 
const stripe = new Stripe(Deno.env.get('STRIPE_SECRET_KEY')!, {
  apiVersion: '2023-10-16',
  httpClient: Stripe.createFetchHttpClient(),
});
 
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')!
  );
 
  if (event.type === 'checkout.session.completed') {
    const session = event.data.object;
    await activateSubscription(session.customer_email);
  }
 
  return new Response(JSON.stringify({ received: true }));
});

Local Development

# Serve functions locally (requires Docker)
supabase start
supabase functions serve
 
# Test with curl
curl -i --location --request POST \
  'http://127.0.0.1:54321/functions/v1/process-document' \
  --header 'Authorization: Bearer [anon-key]' \
  --header 'Content-Type: application/json' \
  --data '{"document_id":"1","content":"test"}'
Metadata Value
Title Supabase Edge Functions: Server-Side Logic Without a Separate Backend
Tool Supabase
Primary SEO keyword supabase edge functions
Secondary keywords supabase edge functions deno, supabase serverless, supabase webhook, supabase openai
Estimated read time 8 minutes
Research date 2026-04-14