Supabase Edge Functions are Deno-based serverless functions that let you run TypeScript code close to your users, reducing latency and enabling real-time features.

Let’s see one in action. Imagine a simple function that greets a user by name.

First, you’d create a new file, say functions/greet.ts:

import { serve } from "https://deno.land/std@0.177.0/http/server.ts";

console.log("Hello from greet.ts!");

serve(async (req) => {
  const { name } = await req.json();
  const greeting = `Hello, ${name || "stranger"}!`;

  return new Response(JSON.stringify({ greeting }), {
    headers: { "content-type": "application/json" },
  });
});

This function uses Deno’s standard library http module to create a web server. It expects a JSON payload with a name property and returns a JSON response containing a greeting.

To deploy this, you’d use the Supabase CLI:

supabase functions deploy greet --no-verify-token

The --no-verify-token flag is useful during development to skip authentication checks. Once deployed, you can invoke it using curl or directly from your Supabase client.

Here’s how you’d call it from your frontend using the Supabase JavaScript client:

import { createClient } from '@supabase/supabase-js';

const supabaseUrl = 'YOUR_SUPABASE_URL';
const supabaseKey = 'YOUR_SUPABASE_ANON_KEY';
const supabase = createClient(supabaseUrl, supabaseKey);

async function sayHello() {
  const { data, error } = await supabase.functions.invoke('greet', {
    body: { name: 'Alice' }
  });

  if (error) {
    console.error('Error invoking function:', error);
  } else {
    console.log('Function response:', data); // { greeting: 'Hello, Alice!' }
  }
}

sayHello();

The invoke method handles the API call to your deployed Edge Function.

Under the hood, Supabase Edge Functions leverage Deno Deploy, a global edge computing platform. When you deploy your function, Deno Deploy spins up instances of your code on servers located in data centers all over the world. When a request comes in, it’s routed to the nearest available instance, minimizing network latency. This is why they’re called "Edge" Functions.

The core problem these functions solve is the need for backend logic that is both fast and scalable, without the overhead of managing traditional servers. You write your code in TypeScript (or JavaScript), and Deno handles the runtime environment, including its security model (explicit permissions) and built-in tooling. Supabase integrates this seamlessly into its platform, allowing you to manage your functions alongside your database, authentication, and storage.

You can also use environment variables to configure your functions. For example, if your function needed an API key for a third-party service, you’d set it in your Supabase project settings under "Edge Functions" and access it in your Deno code like this:

const apiKey = Deno.env.get("THIRD_PARTY_API_KEY");
if (!apiKey) {
  throw new Error("THIRD_PARTY_API_KEY environment variable not set.");
}
// Use apiKey for your API calls...

This keeps sensitive information out of your codebase and allows you to manage it per environment (local, staging, production).

A common pattern is to use Deno’s import maps to manage dependencies. Instead of hardcoding URLs for standard library modules or external libraries, you can define them in an import_map.json file:

{
  "imports": {
    "std/": "https://deno.land/std@0.177.0/"
  }
}

Then, in your TypeScript code, you can import like this:

import { serve } from "std/http/server.ts";

When you deploy via the Supabase CLI, it automatically bundles your function and its dependencies, respecting your import map. This makes managing dependencies cleaner and more robust.

The next step in leveraging Edge Functions is often integrating them with Supabase Realtime subscriptions to build truly dynamic, real-time applications.

Want structured learning?

Take the full Supabase course →