Guide for writing Netlify Edge Functions. Use when building middleware, geolocation-based logic, request/response manipulation, authentication checks, A/B testing, or any low-latency edge compute. Covers Deno runtime, context.next() middleware pattern, geolocation, and when to choose edge vs serverless.
---
name: netlify-edge-functions
description: Guide for writing Netlify Edge Functions. Use when building middleware, geolocation-based logic, request/response manipulation, authentication checks, A/B testing, or any low-latency edge compute. Covers Deno runtime, context.next() middleware pattern, geolocation, and when to choose edge vs serverless.
---
# Netlify Edge Functions
Edge functions run on Netlify's globally distributed edge network (Deno runtime), providing low-latency responses close to users.
## Syntax
```typescript
import type { Config, Context } from "@netlify/edge-functions";
export default async (req: Request, context: Context) => {
return new Response("Hello from the edge!");
};
export const config: Config = {
path: "/hello",
};
```
Place files in `netlify/edge-functions/`. Uses `.ts`, `.js`, `.tsx`, or `.jsx` extensions.
## Config Object
```typescript
export const config: Config = {
path: "/api/*", // URLPattern path(s)
excludedPath: "/api/public/*", // Exclusions
method: ["GET", "POST"], // HTTP methods
onError: "bypass", // "fail" (default), "bypass", or "/error-page"
cache: "manual", // Enable response caching
};
```
## Middleware Pattern
Use `context.next()` to invoke the next handler in the chain and optionally modify the response:
```typescript
export default async (req: Request, context: Context) => {
// Before: modify request or short-circuit
if (!isAuthenticated(req)) {
return new Response("Unauthorized", { status: 401 });
}
// Continue to origin/next function
const response = await context.next();
// After: modify response
response.headers.set("x-custom-header", "value");
return response;
};
```
Return `undefined` to pass through without modification:
```typescript
export default async (req: Request, context: Context) => {
if (!shouldHandle(req)) return; // continues to next handler
return new Response("Handled");
};
```
## Geolocation and IP
```typescript
export default async (req: Request, context: Context) => {
const { city, country, subdivision, timezone } = context.geo;
const ip = context.ip;
if (country?.code === "DE") {
return Response.redirect(new URL("/de", req.url));
}
};
```
Local dev with mocked geo: `netlify dev --geo=mock --country=US`
## Environment Variables
Use `Netlify.env` (not `process.env` or `Deno.env`):
```typescript
const secret = Netlify.env.get("API_SECRET");
```
## Module Support
- **Node.js builtins**: `import { randomBytes } from "node:crypto";`
- **npm packages**: Install via npm and import by name
- **Deno modules**: URL imports (e.g., `import X from "https://esm.sh/package"`)
For URL imports, use an import map:
```json
// import_map.json
{ "imports": { "html-rewriter": "https://ghuc.cc/worker-tools/html-rewriter/index.ts" } }
```
```toml
# netlify.toml
[functions]
deno_import_map = "./import_map.json"
```
## When to Use Edge vs Serverless
| Use Edge Functions for | Use Serverless Functions for |
|---|---|
| Low-latency responses | Long-running operations (up to 15 min) |
| Request/response manipulation | Complex Node.js dependencies |
| Geolocation-based logic | Database-heavy operations |
| Auth checks and redirects | Background/scheduled tasks |
| A/B testing, personalization | Tasks needing > 512 MB memory |
## Limits
| Resource | Limit |
|---|---|
| CPU time | 50 ms per request |
| Memory | 512 MB per deployed set |
| Response header timeout | 40 seconds |
| Code size | 20 MB compressed |
Creator's repository · netlify/context-and-tools