Platform primitives /Edge Functions /

Edge Functions API

This page provides an overview of key concepts as well as a full reference.

# Overview

Use TypeScript or JavaScript to create an edge function file that exports a default function responsible for processing a request.

When the function is invoked, it receives two arguments:

The expected return value is one of the following:

  • a standard Response object representing the HTTP response to be delivered to the client
  • a standard URL object if you want to rewrite the incoming request to another same-site URL with a 200 status code
  • undefined if you choose to bypass the current function

# Edge function types

For TypeScript, you can import the types for the Context and Config objects from @netlify/edge-functions. The types for the Request and Response objects are in the global scope.

import type { Config, Context } from "@netlify/edge-functions";

export default async (request: Request, context: Context) => {
  // ...
};

export const config: Config = {
  path: "/",
};

# Request handling

Edge functions can handle requests in the following ways:

Looking for a list of available request headers?

Netlify doesn’t add specific headers to edge function requests. To find information about the client request, use the context object instead.

# Return a response

Similar to serverless functions and other endpoints, an edge function can just return a standard Response object. Once the function returns the response, the request chain ends and any redirects declared for that path do not occur.

For example, this edge function returns the string Hello, World! as text/html:

export default async () => {
  return new Response("Hello, World!", {
    headers: { "content-type": "text/html" }
  });
};

# Return a redirect

You can use an edge function to return an HTTP redirect to any URL of your choice.

To do this, use the standard Response.redirect function, as shown in the example below.

export default async (req: Request, { cookies, geo }: Context) => {
  if (
    geo.city === "Paris" &&
    cookies.get("promo-code") === "15-for-followers"
  ) {
    const url = new URL("/subscriber-sale", req.url);

    return Response.redirect(url);
  }
};

# Return a rewrite

Similar to our static routing engine, an edge function can also return a rewrite, which is a redirect with a 200 status code. This means that the URL in the visitor’s address bar remains the same, while Netlify’s servers fetch the new location behind the scenes.

To do this, return a standard URL object with the path you want to rewrite to.

export default async (request: Request, { cookies, geo }: Context) => {
  if (
    geo.city === "Paris" &&
    cookies.get("promo-code") === "15-for-followers"
  ) {
    return new URL("/subscriber-sale", request.url);
  }
};

Same-site URLs only

Edge functions can rewrite to only same-site URLs. To fetch content hosted on another Netlify site or an external site, use the fetch Web API.

# Modify a response

An edge function can act as middleware that modifies and returns the response of subsequent functions or requests. This kind of edge function calls context.next() to continue the request chain and waits for a response to return before finishing execution.

Any edge functions that return undefined or use an empty return; also continue the request chain.

Once all edge functions for the initial path run, Netlify evaluates any redirect rules declared for that path and then continues the request chain to eventually serve static content or return a response from a serverless function. For more details on the order of events, review our docs on the declaration processing order.

For example, this edge function uses context.next() to transform the content of the HTTP response to the requested path:

import type { Context } from "@netlify/edge-functions";

export default async (request: Request, context: Context) => {
  const url = new URL(request.url);

  // Look for the query parameter, and return if we don't find it
  if (url.searchParams.get("method") !== "transform") {
    return;
  }

  const response = await context.next();
  const text = await response.text();

  return new Response(text.toUpperCase(), response);
};

If you want to modify and return the content of a path other than the requested one, use fetch() to retrieve it.

export default async (req: Request) => {
  const url = new URL("/welcome", req.url);
  const res = await fetch(url);

  return someTransformationFunction(res);
};

export const config = { path: "/hello" };
# Use conditional request

When using context.next() to transform a response, we modify the request to the downstream asset so that conditional requests don’t apply and you always get a full response back.

If you want full control over the client caching behavior and you’d like to use conditional requests, you should pass the sendConditionalRequest to the context.next() call.

export default async (req: Request, { next }: Context) => {
  const res = await next({ sendConditionalRequest: true });

  // If the response is a 304, it’s cached in the client and we can return it
  if (res.status === 304) {
    return res;
  }

  // Transform the response however you need
  const text = await res.text();

  return new Response(text.toUpperCase(), res);
};
# Read request body

If you want to read the request body in your edge function, you need to explicitly pass on a new request with an unused body when you call context.next() afterwards. For example, context.next(new Request(...)). Without this, attempts to read the request body in subsequent edge functions will cause an error because a request body can only be read once.

export default async (req: Request, context: Context) => {
  const body = await req.json();

  if (!isValid(body.access_token)) {
    return new Response("forbidden", { status: 403 });
  }

  return context.next(new Request(req, { body: JSON.stringify(body) }));
};

# Runtime environment

Edge functions run in a Deno runtime environment that supports many standard Web APIs.

Edge Functions support Node.js built-in modules and Deno modules. Support for npm packages is in beta.

  • For Node.js built-in modules, prefix the import with node:, for example import { randomBytes } from "node:crypto".
  • For Deno modules, use a URL import. You can do this directly in the edge function code, for example import React from "https://esm.sh/react", or by using an import map.
  • For npm packages, install them using npm install or your favorite package manager. Then import them using the package name, for example import _ from "lodash". Support for npm modules is in beta, and some packages that rely on native binaries (like Prisma) or dynamically importing a file at runtime (like cowsay) might not work correctly. Please share feedback and bug reports in the forums.

Edge functions have access to environment variables in the runtime environment. If you have the option to set specific scopes for your environment variables, the scope must include Functions to be available to edge functions during runtime. Learn more about how to set and use environment variables with functions.

# Import maps

When you import third-party modules in your edge function, it can be cumbersome to repeat the module’s full URL in every import statement.

To use module names in your import statements, use an import map file to map module URLs to names. Netlify edge functions support separate import map files instead of import maps defined in deno.json. You can place the import map file anywhere in the project directory. For example, this file maps html-rewriter to https://ghuc.cc/worker-tools/html-rewriter/index.ts:

{
  "imports": {
    "html-rewriter": "https://ghuc.cc/worker-tools/html-rewriter/index.ts"
  }
}

To enable the import map, declare it in netlify.toml:

[functions]
  deno_import_map = "./path/to/your/import_map.json"

You can now use html-rewriter as a shorthand for the module URL.

import { HTMLRewriter } from "html-rewriter";

export default async (request, context) => {
  return new HTMLRewriter()
    .on("p", {
      element(element) {
        element.tagName = "h1";
      }
    })
    .transform(await context.next());
};

# Reference

This reference covers the following:

You may encounter undocumented APIs as you work with Edge Functions. These are not supported in any way and you should not use them. Using undocumented APIs may lead to unexpected or broken functionality.

Searching for type definitions?

For TypeScript, you can import the types for the Context and Config objects from @netlify/edge-functions. The types for the Request and Response objects are in the global scope.

# Netlify-specific Context object

The Context object exposes the following properties:

  • account: an object containing Netlify team account information with the following property:

    • id: unique ID of the team that the site and function belong to.
  • cookies: a simplified interface for reading and storing cookies:

    • cookies.get(name): reads a cookie with a given name from the incoming request.

    • cookies.set(options): sets a cookie on the outgoing response, using the same format as the options value in the CookieStore.set web standard.

    • cookies.delete(name) or cookies.delete(options): adds an instruction to the outgoing response for the client to delete a cookie. Following the CookieStore.delete web standard, accepts a string representing the name of the cookie, or an options object.

      Setting cookies across subdomains only works for custom domains

      netlify.app is listed in the Mozilla Foundation’s Public Suffix List, which prevents setting cookies across subdomains. You can only set a cookie for all subdomains if your site uses a custom domain instead of yoursitename.netlify.app.

  • deploy: an object containing Netlify deploy information with the following properties:

    • context: the context of the deploy that the function belongs to.
    • id: unique ID of the deploy that the function belongs to.
    • published: a boolean that indicates whether or not the function belongs to the current published deploy.
  • geo: an object containing geolocation data for the client with the following properties:

    • city: name of the city.
    • country:
      • code: ISO 3166 code for the country.
      • name: name of the country.
    • latitude: latitude of the location.
    • longitude: longitude of the location.
    • subdivision:
      • code: ISO 3166 code for the country subdivision.
      • name: name of the country subdivision.
    • timezone: timezone of the location.
    • postalCode: postal (zip) code of the location. We support all regional formats, so the format will vary.
  • ip: a string containing the client IP address.

  • requestId: a string containing the Netlify request ID; for example, 01FDWR77JMF2DA1CHF5YA6H07C.

  • next(options?): invokes the next item in the request chain. The method returns a Promise containing the Response from the origin that your edge function can modify before returning. Use this method only if you need access to the response body.

    Accepts an optional options object with the following property:

    • sendConditionalRequest: set to true if you’d like to use conditional requests.
  • next(request, options?): same method as above, except this one explicitly requires a Request object. This variation allows you to read the request body in your edge function and then pass a new request object with an unread body to the next item in the request chain. Without this, the next() call could fail as a request body can only be read once.

  • server: an object containing server metadata with the following property:

    • region: the region code where the deployment is running; for example, us-east1.
  • site: an object containing Netlify site metadata with the following properties:

    • id: unique ID for the site; for example, 1d01c0c0-4554-4747-93b8-34ce3448ab95.
    • name: name of the site, its Netlify subdomain; for example, petsof.
    • url: URL representing the main address to your site. It can be either a Netlify subdomain or your own custom domain if you set one; for example, https://petsof.netlify.app or https://www.petsofnetlify.com.

# Netlify global object

The Netlify global object exposes the following properties:

  • context: the Netlify-specific context object.

    This property is scope-dependent

    The context object is only available when Netlify.context is accessed from within the scope of a function handler or one of its child scopes. If accessed from somewhere else, like the global scope, it returns null.

  • env: an object providing access to environment variables with the following properties:

    • delete(name): in the context of the invocation, deletes an environment variable with a given name.
    • get(name): returns the string value of an environment variable with a given name; if the environment variable is not defined, undefined is returned.
    • has(name): returns a boolean value containing true if an environment variable with a given name exists, and false otherwise.
    • set(name, value): in the context of the invocation, sets an environment variable with a given name and value.
    • toObject(): returns a plain object containing all the environment variables and their values.

# Web APIs

Edge Functions support the following Web APIs: