Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/docs/app/reference/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export default async function ReferencePage(props: { params: Promise<{ slug: Arr
const { sdkId, maybeVersion, path } = parsedPath

const sdkData = REFERENCES[sdkId]
if (sdkData.enabled === false) {
notFound()
}

const latestVersion = sdkData.versions[0]
const version = maybeVersion ?? latestVersion

Expand Down
3 changes: 3 additions & 0 deletions apps/docs/components/Navigation/Navigation.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export interface NavMenuSection {
name: string
url?: `/${string}` | `https://${string}`
items: Partial<NavMenuSection>[]
icon?: string
hasLightIcon?: boolean
isDarkMode?: boolean
enabled?: boolean
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ComponentProps } from 'react'

import { isFeatureEnabled } from 'common'
import { isFeatureEnabled } from 'common/enabled-features'
import type { IconPanel } from 'ui-patterns/IconPanel'
import type { GlobalMenuItems, NavMenuConstant, NavMenuSection } from '../Navigation.types'

Expand Down Expand Up @@ -460,7 +460,7 @@ export const NativeMobileLoginItems = [
},
]

export const SocialLoginItems = [
export const SocialLoginItems: Array<Partial<NavMenuSection>> = [
{
name: 'Google',
icon: '/docs/img/icons/google-icon',
Expand Down Expand Up @@ -591,7 +591,7 @@ export const PhoneLoginsItems = [
},
]

export const auth = {
export const auth: NavMenuConstant = {
icon: 'auth',
title: 'Auth',
items: [
Expand Down Expand Up @@ -1440,6 +1440,10 @@ export const functions: NavMenuConstant = {
name: 'Development Environment',
url: '/guides/functions/development-environment' as `/${string}`,
},
{
name: 'Architecture',
url: '/guides/functions/architecture',
},
],
},
{
Expand Down Expand Up @@ -1865,7 +1869,7 @@ export const storage: NavMenuConstant = {
],
}

export const vectorIndexItems = [
export const vectorIndexItems: Array<Partial<NavMenuSection>> = [
{
name: 'HNSW indexes',
url: '/guides/ai/vector-indexes/hnsw-indexes',
Expand All @@ -1876,7 +1880,7 @@ export const vectorIndexItems = [
},
]

export const ai = {
export const ai: NavMenuConstant = {
icon: 'ai',
title: 'AI & Vectors',
url: '/guides/ai',
Expand Down
29 changes: 28 additions & 1 deletion apps/docs/content/guides/functions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: 'Edge Functions'
description: 'Globally distributed TypeScript functions.'
subtitle: 'Globally distributed TypeScript functions.'
sidebar_label: 'Overview'
hideToc: true
tocVideo: 'za_loEtS4gs'
---

Edge Functions are server-side TypeScript functions, distributed globally at the edge—close to your users. They can be used for listening to webhooks or integrating your Supabase project with third-parties [like Stripe](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/stripe-webhooks). Edge Functions are developed using [Deno](https://deno.com), which offers a few benefits to you as a developer:
Expand All @@ -14,6 +14,33 @@ Edge Functions are server-side TypeScript functions, distributed globally at the
- It is TypeScript first and supports WASM.
- Edge Functions are globally distributed for low-latency.

## How it works

- **Request enters an edge gateway (relay)** — the gateway routes traffic, handles auth headers/JWT validation, and applies routing/traffic rules.
- **Auth & policies are applied** — the gateway (or your function) can validate Supabase JWTs, apply rate-limits, and centralize security checks before executing code.
- **[Edge runtime](https://github.com/supabase/edge-runtime) executes your function** — the function runs on a regionally-distributed Edge Runtime node closest to the user for minimal latency.
- **Integrations & data access** — functions commonly call Supabase APIs (Auth, Postgres, Storage) or third-party APIs. For Postgres, prefer connection strategies suited for edge/serverless environments (see the `connect-to-postgres` guide).
- **Observability and logs** — invocations emit logs and metrics you can explore in the dashboard or downstream monitoring (Sentry, etc.).
- **Response returns via the gateway** — the gateway forwards the response back to the client and records request metadata.

## Quick technical notes

- **Runtime:** Supabase Edge Runtime (Deno compatible runtime with TypeScript first). Functions are simple `.ts` files that export a handler.
- **Local dev parity:** Use Supabase CLI for a local runtime similar to production for faster iteration (`supabase functions serve` command).
- **Global deployment:** Deploy your Edge Functions via Supabase Dashboard, CLI or MCP.
- **Cold starts & concurrency:** cold starts are possible — design for short-lived, idempotent operations. Heavy long-running jobs should be moved to [background workers](/docs/guides/functions/background-tasks).
- **Database connections:** treat Postgres like a remote, pooled service — use connection pools or serverless-friendly drivers.
- **Secrets:** store credentials in Supabase [project secrets](/docs/reference/cli/supabase-secrets) and access them via environment variables.

## When to use Edge Functions

- Authenticated or public HTTP endpoints that need low latency.
- Webhook receivers (Stripe, GitHub, etc.).
- On-demand image or Open Graph generation.
- Small AI inference tasks or orchestrating calls to external LLM APIs (like OpenAI)
- Sending transactional emails.
- Building messaging bots for Slack, Discord, etc.

<div className="not-prose">
<Button size="medium" asChild>
<a href="/docs/guides/functions/quickstart">Get started</a>
Expand Down
107 changes: 107 additions & 0 deletions apps/docs/content/guides/functions/architecture.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
id: 'architecture'
title: 'Edge Functions Architecture'
description: 'Guide to Supabase Edge Functions: Architecture and How They Work'
subtitle: 'Understanding the Architecture of Supabase Edge Functions'
tocVideo: 'za_loEtS4gs'
---

This guide explains the architecture and inner workings of Supabase Edge Functions, based on the concepts demonstrated in the video "Supabase Edge Functions Explained". Edge functions are serverless compute resources that run at the edge of the network, close to users, enabling low-latency execution for tasks like API endpoints, webhooks, and real-time data processing. This guide breaks down Edge Functions into key sections: an example use case, deployment process, global distribution, and execution mechanics.

## 1. Understanding Edge Functions through an example: Image filtering

To illustrate how edge functions operate, consider a photo-sharing app where users upload images and apply filters (e.g., grayscale or sepia) before saving them.

- **Workflow Overview**:

- A user uploads an original image to Supabase Storage.
- When the user selects a filter, the client-side app (using the Supabase JavaScript SDK) invokes an edge function named something like "apply-filter."
- The edge function:
1. Downloads the original image from Supabase Storage.
2. Applies the filter using a library like ImageMagick.
3. Uploads the processed image back to Storage.
4. Returns the path to the filtered image to the client.

- **Why Edge Functions?**:
- They handle compute-intensive tasks without burdening the client device or the database.
- Execution happens server-side but at the edge, ensuring speed and scalability.
- Developers define the function in a simple JavaScript file within the Supabase functions directory.

This example highlights edge functions as lightweight, on-demand code snippets that integrate seamlessly with Supabase services like Storage and Auth.

## 2. Deployment process

Deploying an edge function is straightforward and automated, requiring no manual server setup.

- **Steps to Deploy**:

1. Write the function code in your local Supabase project (e.g., in `supabase/functions/apply-filter/index.ts`).
2. Run the command `supabase functions deploy apply-filter` via the Supabase CLI.
3. The CLI bundles the function and its dependencies into an **ESZip file**—a compact format created by Deno that includes a complete module graph for quick loading and execution.
4. The bundled file is uploaded to Supabase's backend.
5. Supabase generates a unique URL for the function, making it accessible globally.

- **Key Benefits of Deployment**:
- Automatic handling of dependencies and bundling.
- No need to manage infrastructure; Supabase distributes the function across its global edge network.

Once deployed, the function is ready for invocation from anywhere, with Supabase handling scaling and availability.

## 3. Global distribution and routing

Edge functions leverage a distributed architecture to minimize latency by running code close to the user.

- **Architecture Components**:

- **Global API Gateway**: Acts as the entry point for all requests. It uses the requester's IP address to determine geographic location and routes the request to the nearest edge location (e.g., routing a request from Amsterdam to Frankfurt).
- **Edge Locations**: Supabase's network of data centers worldwide where functions are replicated. The ESZip bundle is automatically distributed to these locations upon deployment.
- **Routing Logic**: Based on geolocation mapping, ensuring the function executes as close as possible to the user for optimal performance.

- **How Distribution Works**:
- Post-deployment, the function is propagated to all edge nodes.
- This setup eliminates the need for developers to configure CDNs or regional servers manually.

This global edge network is what makes edge functions "edge-native," providing consistent performance regardless of user location.

## 4. Execution mechanics: Fast and isolated

The core of edge functions' efficiency lies in their execution environment, which prioritizes speed, isolation, and scalability.

- **Request Handling**:

1. A client sends an HTTP request (e.g., POST) to the function's URL, including parameters like auth headers, image ID, and filter type.
2. The global API gateway routes it to the nearest edge location.
3. At the edge, Supabase's **edge runtime** validates the request (e.g., checks authorization).

- **Execution Environment**:

- A new **V8 isolate** is spun up for each invocation. V8 is the JavaScript engine used by Chrome and Node.js, providing a lightweight, sandboxed environment.
- Each isolate has its own memory heap and execution thread, ensuring complete isolation—no interference between concurrent requests.
- The ESZip bundle is loaded into the isolate, and the function code runs.
- After execution, the response (e.g., filtered image path) is sent back to the client.

- **Performance Optimizations**:

- **Cold Starts**: Even initial executions are fast (milliseconds) due to the compact ESZip format and minimal Deno runtime overhead.
- **Warm Starts**: Isolates can remain active for a period (plan-dependent) to handle subsequent requests without restarting.
- **Concurrency**: Multiple isolates can run simultaneously in the same edge location, supporting high traffic.

- **Isolation and Security**:
- Isolates prevent side effects from one function affecting others, enhancing reliability.
- No persistent state; each run is stateless, ideal for ephemeral tasks.

Compared to traditional serverless or monolithic architectures, this setup offers lower latency, automatic scaling, and no infrastructure management, making it perfect for global apps.

## Benefits and use cases

- **Advantages**:

- **Low Latency**: Proximity to users reduces round-trip times.
- **Scalability**: Handles variable loads without provisioning servers.
- **Developer-Friendly**: Focus on code; Supabase manages the rest.
- **Cost-Effective**: Pay-per-use model, with fast execution minimizing costs.

- **Common Use Cases**:
- Real-time data transformations (e.g., image processing).
- API integrations and webhooks.
- Personalization and A/B testing at the edge.
17 changes: 16 additions & 1 deletion apps/docs/content/navigation.references.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
import { isFeatureEnabled } from 'common/enabled-features'

const {
sdkCsharp: sdkCsharpEnabled,
sdkDart: sdkDartEnabled,
sdkKotlin: sdkKotlinEnabled,
sdkPython: sdkPythonEnabled,
sdkSwift: sdkSwiftEnabled,
} = isFeatureEnabled(['sdk:csharp', 'sdk:dart', 'sdk:kotlin', 'sdk:python', 'sdk:swift'])

export const REFERENCES = {
javascript: {
type: 'sdk',
Expand Down Expand Up @@ -35,6 +45,7 @@ export const REFERENCES = {
specFile: 'supabase_dart_v1',
},
},
enabled: sdkDartEnabled,
},
csharp: {
type: 'sdk',
Expand All @@ -53,6 +64,7 @@ export const REFERENCES = {
specFile: 'supabase_csharp_v0',
},
},
enabled: sdkCsharpEnabled,
},
swift: {
type: 'sdk',
Expand All @@ -71,6 +83,7 @@ export const REFERENCES = {
specFile: 'supabase_swift_v1',
},
},
enabled: sdkSwiftEnabled,
},
kotlin: {
type: 'sdk',
Expand All @@ -93,6 +106,7 @@ export const REFERENCES = {
specFile: 'supabase_kt_v1',
},
},
enabled: sdkKotlinEnabled,
},
python: {
type: 'sdk',
Expand All @@ -107,6 +121,7 @@ export const REFERENCES = {
specFile: 'supabase_py_v2',
},
},
enabled: sdkPythonEnabled,
},
cli: {
type: 'cli',
Expand Down Expand Up @@ -160,7 +175,7 @@ export const REFERENCES = {
} as const

export const clientSdkIds = Object.keys(REFERENCES).filter(
(reference) => REFERENCES[reference].type === 'sdk'
(reference) => REFERENCES[reference].type === 'sdk' && REFERENCES[reference].enabled !== false
)

export const selfHostingServices = Object.keys(REFERENCES).filter(
Expand Down
33 changes: 29 additions & 4 deletions apps/docs/features/docs/GuidesMdx.utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { BASE_PATH } from '~/lib/constants'
import { GUIDES_DIRECTORY, isValidGuideFrontmatter, type GuideFrontmatter } from '~/lib/docs'
import { GuideModelLoader } from '~/resources/guide/guideModelLoader'
import { newEditLink } from './GuidesMdx.template'
import { checkGuidePageEnabled } from './NavigationPageStatus.utils'

const PUBLISHED_SECTIONS = [
'ai',
Expand All @@ -42,6 +43,8 @@ const PUBLISHED_SECTIONS = [
const getGuidesMarkdownInternal = async (slug: string[]) => {
const relPath = slug.join(sep).replace(/\/$/, '')
const fullPath = join(GUIDES_DIRECTORY, relPath + '.mdx')
const guidesPath = `/guides/${slug.join('/')}`

/**
* SAFETY CHECK:
* Prevent accessing anything outside of published sections and GUIDES_DIRECTORY
Expand All @@ -53,6 +56,15 @@ const getGuidesMarkdownInternal = async (slug: string[]) => {
notFound()
}

/**
* DISABLED PAGE CHECK:
* Check if this page is disabled in the navigation configuration
*/
if (!checkGuidePageEnabled(guidesPath)) {
console.log('Page is disabled: %s', guidesPath)
notFound()
}

try {
const guide = (await GuideModelLoader.fromFs(relative(GUIDES_DIRECTORY, fullPath))).unwrap()
const content = guide.content ?? ''
Expand Down Expand Up @@ -121,12 +133,25 @@ const genGuidesStaticParams = (directory?: string) => async () => {
)
)

// Flattening earlier will not work because there is nothing to flatten
// until the promises resolve.
const allParams = (await Promise.all(promises)).flat()

/**
* Flattening earlier will not work because there is nothing to flatten
* until the promises resolve.
* Filter out disabled pages from static generation
*/
const result = (await Promise.all(promises)).flat()
return result
const enabledParams = allParams.filter((param) => {
const guidesPath = `/guides/${directory ? `${directory}/` : ''}${param.slug.join('/')}`
const isEnabled = checkGuidePageEnabled(guidesPath)

if (!isEnabled) {
console.log('Excluding disabled page from static generation: %s', guidesPath)
}

return isEnabled
})

return enabledParams
}

const genGuideMeta =
Expand Down
Loading
Loading