Home

Edge Functions Quickstart

Learn how to build an Edge Function locally and deploy it to the Supabase Platform in less than 7 minutes.

Prerequisites#

Follow the steps to prepare your Supabase project on your local machine.

  • Install the Supabase CLI. Docs.
  • Login to the CLI using the command: supabase login. Docs.
  • Initialize Supabase inside your project using the command: supabase init. Docs.
  • Link to your Remote Project using the command supabase link --project-ref your-project-ref. Docs.
  • Setup your environment: Follow the steps below.

Create an Edge Function#

Let's create a new Edge Function called hello-world inside your project:


_10
supabase functions new hello-world

This creates a function stub in your supabase folder at ./functions/hello-world/index.ts.

Deploy to production#

Deploy a specific function#


_10
supabase functions deploy hello-world

This command bundles your Edge Function from ./functions/hello-world/index.ts and deploys it to the Supabase platform. The command outputs a URL to the Supabase Dashboard which you can open to find view more details. Let's open the link to find the execution command.

note

By default, Edge Functions require a valid JWT in the authorization header. This header is automatically set when invoking your function via a Supabase client library.

If you want to use Edge Functions to handle webhooks (e.g. Stripe payment webhooks etc.), you need to pass the --no-verify-jwt flag when deploying your function.

Deploy all functions#


_10
supabase functions deploy

Since Supabase CLI v1.62.0 you can deploy all functions with a single command. This is useful for example when deploying with GitHub Actions.

Individual function configuration like JWT verification and import map location can be set via the config.toml file.


_10
[functions.hello-world]
_10
verify_jwt = false

Invoking remote functions#

You can invoke Edge Functions using curl:


_10
curl --request POST 'https://<project_ref>.supabase.co/functions/v1/hello-world' \
_10
--header 'Authorization: Bearer ANON_KEY' \
_10
--header 'Content-Type: application/json' \
_10
--data '{ "name":"Functions" }'

note

If you receive an error Invalid JWT, find the ANON_KEY of your project in the Dashboard under Settings > API.

or using one of the client libraries, e.g. using supabase-js:


_10
// https://supabase.com/docs/reference/javascript/installing
_10
import { createClient } from '@supabase/supabase-js'
_10
_10
// Create a single supabase client for interacting with your database
_10
const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key')
_10
_10
const { data, error } = await supabase.functions.invoke('hello-world', {
_10
body: { name: 'Functions' },
_10
})

After invoking your Edge Function you should see the response { "message":"Hello Functions!" }.

Error Handling#

When interacting with Edge Functions, it's important to be prepared for potential errors that might occur during the invocation. To handle errors effectively, the following error handling code can be used:


_17
import { FunctionsHttpError, FunctionsRelayError, FunctionsFetchError } from '@supabase/supabase-js'
_17
_17
const { data, error } = await supabase.functions.invoke('hello', {
_17
headers: {
_17
'my-custom-header': 'my-custom-header-value',
_17
},
_17
body: { foo: 'bar' },
_17
})
_17
_17
if (error instanceof FunctionsHttpError) {
_17
const errorMessage = await error.context.json()
_17
console.log('Function returned an error', errorMessage)
_17
} else if (error instanceof FunctionsRelayError) {
_17
console.log('Relay error:', error.message)
_17
} else if (error instanceof FunctionsFetchError) {
_17
console.log('Fetch error:', error.message)
_17
}

In the provided error handling code, we're checking the type of error that occurred using the "instanceof" operator. This helps us differentiate between different types of errors and handle them appropriately. Depending on the type of error, we either log the error message or information specific to that type of error.

This error handling mechanism ensures that your application can gracefully handle errors that might arise during the execution of Edge Functions, providing a more robust user experience.

Importing Node npm modules#

We recommend using esm.sh for importing Node.js modules that are published to npm. To do so you simply put https://esm.sh/ in front of the package name.

For example, when you want to use supabase-js within Supabase Edge Functions, you would import createClient as follows:


_10
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'

As long as your environment is set up properly and the module you're importing is exporting types, the import will have types and autocompletion support.

Setting Up Your Environment#

You can follow the Deno guide for setting up your development environment with your favorite editor/IDE.

Deno with Visual Studio Code (vscode)#

Install the Deno language server via this link or by browsing the extensions in vscode and choosing to install the Deno extension.

Partially Deno enabling a workspace

In a given workspace (or workspace folder), sub-paths can be enabled for Deno, while code outside those paths will be not be enabled and the vscode built-in JavaScript/TypeScript language server will be used.

For example if you have a project like this:


_10
project
_10
├── app
_10
└── supabase
_10
└── functions

Where you only want to enabled the supabase/functions path (and its subpaths) to be Deno enabled, you will want to add ./supabase/functions to the list of Deno: Enable Paths in the configuration. In your .vscode/settings.json file add:


_10
{
_10
"deno.enablePaths": ["./supabase/functions"],
_10
"deno.importMap": "./supabase/functions/import_map.json"
_10
}

Multi-root workspaces

Alternatively, you can utilize multi-root workspaces.

For example, see this edge-functions.code-workspace configuration for a CRA (create react app) client with Supabase Edge Functions. You can find the complete example on GitHub.


_24
{
_24
"folders": [
_24
{
_24
"name": "project-root",
_24
"path": "./"
_24
},
_24
{
_24
"name": "client",
_24
"path": "app"
_24
},
_24
{
_24
"name": "supabase-functions",
_24
"path": "supabase/functions"
_24
}
_24
],
_24
"settings": {
_24
"files.exclude": {
_24
"node_modules/": true,
_24
"app/": true,
_24
"supabase/functions/": true
_24
},
_24
"deno.importMap": "./supabase/functions/import_map.json"
_24
}
_24
}

Database Functions vs Edge Functions#

For data-intensive operations we recommend using Database Functions, which are executed within your database and can be called remotely using the REST and GraphQL API.

For use-cases which require low-latency we recommend Edge Functions, which are globally-distributed and can be written in TypeScript.

Organizing your Edge Functions#

We recommend developing “fat functions”. This means that you should develop few large functions, rather than many small functions. One common pattern when developing Functions is that you need to share code between two or more Functions. To do this, you can store any shared code in a folder prefixed with an underscore (_). We also recommend a separate folder for Unit Tests including the name of the function followed by a -test suffix. We recommend this folder structure:


_16
└── supabase
_16
├── functions
_16
│ ├── import_map.json # A top-level import map to use across functions.
_16
│ ├── _shared
_16
│ │ ├── supabaseAdmin.ts # Supabase client with SERVICE_ROLE key.
_16
│ │ └── supabaseClient.ts # Supabase client with ANON key.
_16
│ │ └── cors.ts # Reusable CORS headers.
_16
│ ├── function-one # Use hyphens to name functions.
_16
│ │ └── index.ts
_16
│ └── function-two
_16
│ │ └── index.ts
_16
│ └── tests
_16
│ └── function-one-test.ts
_16
│ └── function-two-test.ts
_16
├── migrations
_16
└── config.toml

Naming Edge Functions#

We recommend using hyphens to name functions because hyphens are the most URL-friendly of all the naming conventions (snake_case, camelCase, PascalCase).

Using HTTP Methods#

Edge Functions supports GET, POST, PUT, PATCH, DELETE, and OPTIONS. A function can be designed to perform different actions based on a request's HTTP method. See the example on building a RESTful service to learn how to handle different HTTP methods in your function.

Limitations#

  • Deno Deploy limitations
    • Deno does not support outgoing connections to ports 25, 465, and 587.
    • Cannot read or write to File System
    • NPM modules are not supported.
  • Edge Functions
    • Serving of HTML content is not supported (GET requests that return text/html will be rewritten to text/plain).