Edge Functions for Self-Hosted Supabase: Complete Setup Guide

Learn how to deploy and configure Supabase Edge Functions on self-hosted instances, including Docker setup, troubleshooting, and production tips.

Cover Image for Edge Functions for Self-Hosted Supabase: Complete Setup Guide

Edge Functions are one of Supabase's most powerful features—serverless TypeScript functions running on Deno that execute close to your users. But if you've tried to set them up on a self-hosted Supabase instance, you've probably discovered it's not as straightforward as the cloud version.

This guide covers everything you need to know about running Edge Functions on your own infrastructure: from initial setup to production-ready deployment.

The Current State of Self-Hosted Edge Functions

Let's be honest about where things stand. Self-hosted Edge Functions are officially in beta, and Supabase warns that breaking changes to APIs and configuration options will happen. The community has felt this pain—recent JWT verification changes in early 2026 broke many self-hosted deployments without warning.

Here's what you should know:

  • Studio integration is limited: The Edge Functions icon doesn't appear in self-hosted Studio by default
  • Logs can be problematic: Many users report 502 errors when accessing function logs
  • Cron scheduling requires extra setup: Unlike cloud Supabase, scheduled functions need manual configuration
  • Documentation gaps exist: Some features work differently than documented

Despite these challenges, self-hosted Edge Functions absolutely work. You just need to understand the architecture and configuration requirements.

Understanding the Architecture

Supabase Edge Functions run on the Edge Runtime, an open-source Deno-based server that Supabase maintains. When you deploy functions on Supabase Cloud, they run on Deno Deploy with a functions-relay handling authentication and rate limiting.

For self-hosted deployments, you have two options:

  1. Use the bundled edge-functions container in the official Docker Compose stack
  2. Deploy Edge Runtime separately on platforms like Fly.io, Railway, or your own servers

The bundled approach is simpler but less flexible. Deploying separately gives you more control over scaling and geographic distribution.

Setting Up Edge Functions with Docker Compose

If you're running self-hosted Supabase via Docker Compose, Edge Functions are already included—they just need configuration.

Step 1: Verify the Edge Functions Service

Check your docker-compose.yml for the functions service:

functions:
  container_name: supabase-edge-functions
  image: supabase/edge-runtime:v1.69.28
  restart: unless-stopped
  depends_on:
    analytics:
      condition: service_healthy
  environment:
    JWT_SECRET: ${JWT_SECRET}
    SUPABASE_URL: http://kong:8000
    SUPABASE_ANON_KEY: ${ANON_KEY}
    SUPABASE_SERVICE_ROLE_KEY: ${SERVICE_ROLE_KEY}
    SUPABASE_DB_URL: postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/postgres
    VERIFY_JWT: "true"

Step 2: Create Your Functions Directory

Edge Functions are stored in volumes/functions. Create the directory structure:

mkdir -p volumes/functions/hello

Create your first function at volumes/functions/hello/index.ts:

import { serve } from "https://deno.land/[email protected]/http/server.ts"

serve(async (req) => {
  const { name } = await req.json()
  const data = {
    message: `Hello ${name}!`,
  }

  return new Response(
    JSON.stringify(data),
    { headers: { "Content-Type": "application/json" } },
  )
})

Step 3: Configure Environment Variables

Your .env file needs these Edge Function-specific variables:

# Edge Functions
FUNCTIONS_VERIFY_JWT=true

# Make sure these match your existing config
JWT_SECRET=your-super-secret-jwt-key-at-least-32-characters
ANON_KEY=your-anon-key
SERVICE_ROLE_KEY=your-service-role-key

Step 4: Restart and Test

docker compose down
docker compose up -d

Test your function:

curl -X POST 'http://localhost:8000/functions/v1/hello' \
  -H "Authorization: Bearer YOUR_ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "World"}'

Troubleshooting Common Issues

JWT Verification Errors

The most common issue in 2026 is JWT verification failures. Supabase recently transitioned to asymmetric JWT keys, causing errors like:

TypeError: Key for the ES256 algorithm must be of type CryptoKey

Quick fix: Pin to Edge Runtime version 1.69.28 in your docker-compose.yml:

functions:
  image: supabase/edge-runtime:v1.69.28

Long-term solution: Update your JWT configuration to use the new asymmetric format. Check the official migration guide for specifics.

Functions Not Appearing in Studio

Self-hosted Studio doesn't show the Functions sidebar by default. This is a known limitation. You have two options:

  1. Manage functions via CLI: Use supabase functions commands
  2. Deploy through your CI/CD pipeline: Most production setups use automated deployment anyway

502 Errors on Function Logs

If you see "Something went wrong! Unknown error" when accessing logs:

  1. Check that the analytics service is running: docker logs supabase-analytics
  2. Verify the functions container can reach analytics: docker exec supabase-edge-functions ping analytics
  3. Check disk space—log ingestion fails silently when storage is full

Functions Timing Out

The default timeout is 150 seconds. For longer operations:

functions:
  environment:
    FUNCTIONS_TIMEOUT: 300  # 5 minutes

However, consider whether long-running functions are the right approach. Background jobs might be better handled via pg_cron or external job queues.

Deploying Edge Functions Separately

For production workloads, you might want to run Edge Functions on dedicated infrastructure. This gives you:

  • Geographic distribution: Run functions closer to your users
  • Independent scaling: Scale functions without affecting your database
  • Better isolation: Function issues don't impact other Supabase services

Deploying to Fly.io

Supabase provides a demo repository for this exact use case:

# Clone the demo
git clone https://github.com/supabase/self-hosted-edge-functions-demo
cd self-hosted-edge-functions-demo

# Copy your functions
cp -r /path/to/your/functions/* ./functions/

# Deploy to Fly.io
fly launch
fly deploy

Your fly.toml should include:

[env]
  SUPABASE_URL = "https://your-self-hosted-supabase.com"
  
[experimental]
  cmd = ["start", "--main-service", "/usr/services"]

Set secrets via Fly CLI:

fly secrets set JWT_SECRET=your-jwt-secret
fly secrets set SUPABASE_SERVICE_ROLE_KEY=your-service-key

Connecting to Your Self-Hosted Instance

Whether deploying to Fly.io, Railway, or elsewhere, your Edge Functions need to connect back to your Supabase instance. Ensure:

  1. Network connectivity: Functions can reach your Supabase Kong gateway
  2. Correct URLs: Use internal URLs if possible, public URLs otherwise
  3. SSL certificates: If using custom domains, ensure certificates are valid

Scheduled Functions (Cron)

Unlike Supabase Cloud where you can schedule functions through the dashboard, self-hosted requires manual cron setup.

Option 1: pg_cron Extension

Use PostgreSQL's built-in cron capabilities:

-- Enable the extension
create extension if not exists pg_cron;

-- Schedule a function call every hour
select cron.schedule(
  'hourly-cleanup',
  '0 * * * *',
  $$
  select net.http_post(
    url := 'http://functions:9000/functions/v1/cleanup',
    headers := '{"Authorization": "Bearer YOUR_SERVICE_ROLE_KEY"}'::jsonb
  );
  $$
);

Option 2: External Cron Service

Use a dedicated cron service like:

  • Cron-job.org (free tier available)
  • GitHub Actions scheduled workflows
  • Your server's crontab
# crontab -e
0 * * * * curl -X POST 'https://your-supabase.com/functions/v1/cleanup' \
  -H "Authorization: Bearer SERVICE_ROLE_KEY"

Production Best Practices

1. Always Pin Runtime Versions

Never use latest tags in production:

functions:
  image: supabase/edge-runtime:v1.69.28  # Specific version

2. Implement Health Checks

Add a health check endpoint to catch issues early:

functions:
  healthcheck:
    test: ["CMD", "curl", "-f", "http://localhost:9000/health"]
    interval: 30s
    timeout: 10s
    retries: 3

3. Set Resource Limits

Prevent runaway functions from consuming all resources:

functions:
  deploy:
    resources:
      limits:
        cpus: '2'
        memory: 2G
      reservations:
        cpus: '0.5'
        memory: 512M

4. Use Environment-Specific Secrets

Never hardcode secrets. Use Docker secrets or environment files:

functions:
  secrets:
    - jwt_secret
    - service_role_key

5. Monitor Function Performance

Set up monitoring to track:

  • Invocation counts
  • Error rates
  • Response times
  • Memory usage

Tools like Prometheus and Grafana work well for this.

When to Use Edge Functions vs. Alternatives

Edge Functions are great for:

  • Webhook handlers: Processing Stripe, GitHub, or other webhook events
  • API proxies: Adding authentication or transforming external API responses
  • Light computation: Quick data transformations or validations

Consider alternatives for:

  • Heavy computation: Use dedicated workers or background job systems
  • Long-running tasks: pg_cron with database functions might be simpler
  • Complex business logic: A dedicated API server gives you more control

Simplifying Edge Function Management

Managing Edge Functions on self-hosted Supabase requires more manual work than the cloud version. Supascale can help by providing:

  • A unified interface for managing functions across multiple projects
  • Simplified deployment workflows
  • Integrated monitoring and logging

Check our pricing page to see how Supascale handles the operational complexity of self-hosted Supabase.

Conclusion

Self-hosted Edge Functions are absolutely viable, but they require more configuration and maintenance than the cloud version. The key is understanding the architecture, staying on stable runtime versions, and having good monitoring in place.

Start with the bundled Docker setup, get comfortable with the basics, then consider separate deployment for production workloads that need geographic distribution or independent scaling.


Further Reading