Edge Functions

Managing dependencies

Managing packages and dependencies.


Importing dependencies

Supabase Edge Functions support several ways to import dependencies:

NPM modules

You can import npm modules using the npm: specifier:


_10
import { createClient } from 'npm:@supabase/supabase-js@2'

Node.js built-ins

For Node.js built-in APIs, use the node: specifier:


_10
import process from 'node:process'

Learn more about npm specifiers and Node built-in APIs in Deno's documentation.

JSR

You can import JS modules published to JSR (eg: Deno's standard library), using the jsr: specifier:


_10
import path from 'jsr:@std/path@1.0.8'

Managing dependencies

Developing with Edge Functions is similar to developing with Node.js, but with a few key differences.

In the Deno ecosystem, each function should be treated as an independent project with its own set of dependencies and configurations. This "isolation by design" approach:

  • Ensures each function has explicit control over its dependencies
  • Prevents unintended side effects between functions
  • Makes deployments more predictable and maintainable
  • Allows for different versions of the same dependency across functions

For these reasons, we recommend maintaining separate configuration files (deno.json/deno.jsonc, .npmrc, or import_map.json) within each function's directory, even if it means duplicating some configurations.

There are two ways to manage your dependencies in Supabase Edge Functions:

Each function should have its own deno.jsonc or deno.json file to manage dependencies and configure Deno-specific settings. This ensures proper isolation between functions and is the recommended approach for deployment. For a complete list of supported options, see the official Deno configuration documentation.

supabase/functions/my-function/deno.json

_10
{
_10
"imports": {
_10
"lodash": "https://cdn.skypack.dev/lodash"
_10
}
_10
}

The recommended file structure for deployment:


_11
└── supabase
_11
├── functions
_11
│ ├── function-one
_11
│ │ ├── index.ts
_11
│ │ ├─- deno.jsonc # Function-specific Deno configuration
_11
│ │ └── .npmrc # Function-specific npm configuration (if needed)
_11
│ └── function-two
_11
│ ├── index.ts
_11
│ ├─- deno.jsonc # Function-specific Deno configuration
_11
│ └── .npmrc # Function-specific npm configuration (if needed)
_11
└── config.toml

Using import maps (legacy)

Import Maps are a legacy way to manage dependencies, similar to a package.json file. While still supported, we recommend using deno.jsonc. If both exist, deno.jsonc takes precedence.

Each function should have its own import_map.json file for proper isolation:

supabase/functions/my-function/import_map.json

_10
{
_10
"imports": {
_10
"lodash": "https://cdn.skypack.dev/lodash"
_10
}
_10
}

The recommended file structure:


_10
└── supabase
_10
├── functions
_10
│ ├── function-one
_10
│ │ ├── index.ts
_10
│ │ └── import_map.json # Function-specific import map
_10
│ └── function-two
_10
│ ├── index.ts
_10
│ └── import_map.json # Function-specific import map
_10
└── config.toml

If using import maps with VSCode, update your .vscode/settings.json to point to your function-specific import map:

settings.json

_10
{
_10
"deno.enable": true,
_10
"deno.unstable": [
_10
"bare-node-builtins",
_10
"byonm"
_10
// ... other flags ...
_10
],
_10
"deno.importMap": "./supabase/functions/my-function/import_map.json"
_10
}

You can override the default import map location using the --import-map <string> flag with serve and deploy commands, or by setting the import_map property in your config.toml file:

supabase/config.toml

_10
[functions.my-function]
_10
import_map = "./supabase/functions/my-function/import_map.json"

Importing from private registries

To use private npm packages, create a .npmrc file within your function directory. This ensures proper isolation and dependency management for each function.


_10
└── supabase
_10
└── functions
_10
└── my-function
_10
├── index.ts
_10
├── deno.jsonc
_10
└── .npmrc # Function-specific npm configuration

Add your registry details in the .npmrc file. Follow this guide to learn more about the syntax of npmrc files.


_10
@myorg:registry=https://npm.registryhost.com
_10
//npm.registryhost.com/:_authToken=VALID_AUTH_TOKEN

After configuring your .npmrc, you can import the private package in your function code:


_10
import MyPackage from 'npm:@myorg/private-package@v1.0.1'
_10
_10
// use MyPackage

Using a custom NPM registry

Some organizations require a custom NPM registry for security and compliance purposes. In such instances, you can specify the custom NPM registry to use via NPM_CONFIG_REGISTRY environment variable.

You can define it in the project's .env file or directly specify it when running the deploy command:


_10
NPM_CONFIG_REGISTRY=https://custom-registry/ supabase functions deploy my-function

Importing types

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

Some npm packages may not ship out of the box types and you may need to import them from a separate package. You can specify their types with a @deno-types directive:


_10
// @deno-types="npm:@types/express@^4.17"
_10
import express from 'npm:express@^4.17'

To include types for built-in Node APIs, add the following line to the top of your imports:


_10
/// <reference types="npm:@types/node" />