new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Supabase · all subjects

ai-tools/edge-functions

64 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

Hugging Face image captioning edge function complete code

import { HfInference } from 'https://esm.sh/@huggingface/inference@2.3.2' import { createClient } from 'npm:@supabase/supabase-js@2' import { Database } from './types.ts' console.log('Hello from `huggingface-image-captioning` function!') const hf = new HfInference(Deno.env.get('HUGGINGFACE_ACCESS_TOKEN')) type SoRecord = Database['storage']['Tables']['objects']['Row'] interface WebhookPayload { type: 'INSERT' | 'UPDATE' | 'DELETE' table: string record: SoRecord schema: 'public' old_record: null | SoRecord } Deno.serve(async (req) => { const payload: WebhookPayload = await req.json() const soRecord = payload.record const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!) const supabaseAdminClient = createClient<Database>( // Supabase API URL - env var exported by default when deployed. Deno.env.get('SUPABASE_URL') ?? '', // Supabase API SECRET KEY - env var exported by default when deployed. SUPABASE_SECRET_KEYS['default'] ?? '' ) // Construct image url from storage const { data, error } = await supabaseAdminClient.storage .from(soRecord.bucket_id!) .createSignedUrl(soRecord.path_tokens!.join('/'), 60) if (error) throw error const { signedUrl } = data // Run image captioning with Huggingface const imgDesc = await hf.imageToText({ data: await (await fetch(signedUrl)).blob(), model: 'nlpconnect/vit-gpt2-image-captioning', }) // Store image caption in Database table await supabaseAdminClient .from('image_caption') .insert({ id: soRecord.id!, caption: imgDesc.generated_text }) .throwOnError() return new Response('ok') })

Database webhook trigger for image captioning

A database webhook can be created in the Supabase Dashboard to trigger an edge function anytime a record is added to the storage.objects table. This enables automatic image captioning when files are uploaded to a storage bucket.

Hugging Face Inference API access via JavaScript SDK

Huggingface.js provides a convenient way to make calls to 100,000+ machine learning models. The HfInference class is imported from 'https://esm.sh/@huggingface/inference@2.3.2' and initialized with a Hugging Face access token from environment variables. The imageToText() method can be used to run image captioning with a specified model like 'nlpconnect/vit-gpt2-image-captioning'.

Hugging Face image captioning edge function setup steps

To set up image captioning with Hugging Face and Supabase: (1) Create a new Supabase project. (2) Create a storage bucket called 'images'. (3) Generate TypeScript types from the remote database. (4) Create a database table called 'image_caption' with an 'id' column of type uuid that references storage.objects.id and a 'caption' column of type text. (5) Regenerate TypeScript types to include the new image_caption table. (6) Deploy the function to Supabase using 'supabase functions deploy huggingface-image-captioning'. (7) Create a database webhook in the Supabase Dashboard to trigger the huggingface-image-captioning function anytime a record is added to the storage.objects table.

Generate TypeScript types for storage and public schemas

To generate a types.ts file for the storage and public schemas, run the command: supabase gen types typescript --project-id=your-project-ref --schema=storage,public > supabase/functions/huggingface-image-captioning/types.ts

Serve edge functions locally

Run `supabase functions serve --env-file ./supabase/.env.local --no-verify-jwt` to serve edge functions locally. The function will be available at `http://localhost:54321/functions/v1/openai`.

Test edge function with curl

Make a POST request to test: `curl -i --location --request POST http://localhost:54321/functions/v1/openai --header 'Content-Type: application/json' --data '{"query":"What is Supabase?}'`

Deploy edge function to cloud

Deploy with `supabase functions deploy --no-verify-jwt openai` and then set secrets with `supabase secrets set --env-file ./supabase/.env.local`.

Stream OpenAI responses word-by-word

Set `stream: true` in the openai.chat.completions.create call to stream GPT's response word-by-word back to the client instead of waiting for the entire response.

Create edge function with supabase CLI

Run `supabase functions new openai` to scaffold a new edge function. This creates a new edge function at `./supabase/functions/openai/index.ts`.

Edge function to call OpenAI completions API

Import OpenAI from `https://deno.land/x/openai@v4.24.0/mod.ts`. Create a Deno.serve handler that reads a JSON POST request with a `query` field, passes it to OpenAI's chat.completions.create with model `gpt-3.5-turbo`, and returns the text response. The example uses `stream: false` to wait for the complete response before returning.

OpenAI API key configuration for edge functions

Store the OpenAI API key in a `.env.local` file in the `./supabase` folder with the format `OPENAI_API_KEY=your-key-here`. Access the key in the edge function using `Deno.env.get('OPENAI_API_KEY')`.

Curl example for testing text-to-image Edge Function

Test a text-to-image Edge Function locally with: curl --output result.jpg --location --request POST 'http://localhost:54321/functions/v1/text-to-image' \ --header 'Content-Type: application/json' \ --data '{"prompt":"Llama wearing sunglasses"}' This saves the generated image to result.jpg locally.

Testing Edge Functions locally with Hugging Face

To serve an Edge Function locally, run 'supabase functions serve --env-file .env.local --no-verify-jwt'. The --env-file parameter loads environment variables from the .env.local file. The --no-verify-jwt flag disables JWT verification for testing purposes. In production, JWT tokens must be passed as Bearer tokens in the Authorization header.

Text-to-image Edge Function example with Hugging Face

Example Edge Function that performs text-to-image generation using Hugging Face Inference API: import { HfInference } from 'https://esm.sh/@huggingface/inference@2.3.2' const hf = new HfInference(Deno.env.get('HUGGING_FACE_ACCESS_TOKEN')) Deno.serve(async (req) => { const { prompt } = await req.json() const image = await hf.textToImage( { inputs: prompt, model: 'stabilityai/stable-diffusion-2', }, { use_cache: false, } ) return new Response(image) }) This function accepts a JSON POST request with a 'prompt' parameter, calls the Hugging Face textToImage() method with the stabilityai/stable-diffusion-2 model, and returns the generated image as a Blob wrapped in a Response.

Edge Function setup for Hugging Face integration

To use Hugging Face with Edge Functions, first run 'supabase init' in your local project if not already initialized. Then create a new Edge Function using 'supabase functions new <function-name>'. Store the Hugging Face access token in a .env.local file with the key HUGGING_FACE_ACCESS_TOKEN. The token is accessible inside Edge Functions via Deno.env.get() and can be safely used server-side.

Testing hybrid_search Edge Function with cURL

To test a hybrid_search Edge Function, make a POST request: curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/hybrid-search' --header 'Authorization: Bearer <anonymous key>' --header 'Content-Type: application/json' --data '{"query":"Italian recipes with tomato sauce"}'

hybrid_search Edge Function example with OpenAI

Example Edge Function calling hybrid_search from JavaScript: import { createClient } from 'npm:@supabase/supabase-js@2' import OpenAI from 'npm:openai' const supabaseUrl = Deno.env.get('SUPABASE_URL')! const supabaseSecretKey = Deno.env.get('SUPABASE_SECRET_KEY')! const openaiApiKey = Deno.env.get('OPENAI_API_KEY')! Deno.serve(async (req) => { const { query } = await req.json() const openai = new OpenAI({ apiKey: openaiApiKey }) const embeddingResponse = await openai.embeddings.create({ model: 'text-embedding-3-large', input: query, dimensions: 512, }) const [{ embedding }] = embeddingResponse.data const supabase = createClient(supabaseUrl, supabaseSecretKey) const { data: documents } = await supabase.rpc('hybrid_search', { query_text: query, query_embedding: embedding, match_count: 10, }) return new Response(JSON.stringify(documents), { headers: { 'Content-Type': 'application/json' }, }) }) This example generates embeddings using OpenAI's text-embedding-3-large model with 512 dimensions, then calls the hybrid_search Postgres function via RPC with the query text, embedding, and match count.

Supabase Edge Functions semantic search model support

Supabase Edge Functions has built-in support for the gte-small embedding model. Other models can be accessed through third-party APIs like OpenAI, or run locally through libraries like Transformers.js for JavaScript implementations.

Example: Edge Function to notify Slack of branch action runs

This Edge Function listens for run completed events and sends notifications to a Slack channel: ```typescript import 'jsr:@supabase/functions-js/edge-runtime.d.ts' console.log('Branching notification booted!') const slack = Deno.env.get('SLACK_WEBHOOK_URL') ?? '' Deno.serve(async (request) => { const body = await request.json() const blocks = [ { type: 'header', text: { type: 'plain_text', text: `Action run ${body.data.action_run.failure ? 'failed' : 'completed'}`, emoji: true, }, }, { type: 'section', fields: [ { type: 'mrkdwn', text: `*Branch ref:*\n${body.data.project_ref}`, }, { type: 'mrkdwn', text: `*Run ID:*\n${body.data.action_run.id}`, }, ], }, { type: 'section', fields: [ { type: 'mrkdwn', text: `*Started at:*\n${body.data.action_run.created_at}`, }, { type: 'mrkdwn', text: `*Completed at:*\n${body.timestamp}`, }, ], }, { type: 'section', text: { type: 'mrkdwn', text: `<${body.data.details_url}|View logs>`, }, }, ] const resp = await fetch(slack, { method: 'POST', body: JSON.stringify({ blocks, }), }) const message = await resp.text() return new Response( JSON.stringify({ message, }), { status: 200, } ) }) ```

Edge Functions JWT verification limitation

Edge Functions only support JWT verification via the `anon` and `service_role` JWT-based API keys. When using publishable and secret keys with Edge Functions, you must use the `--no-verify-jwt` option. The Supabase platform does not verify the `apikey` header when using Edge Functions in this way. Implement your own `apikey`-header authorization logic inside the Edge Function code itself.

Edge Functions use Deno runtime

Supabase Edge Functions run on Deno, a modern runtime for JavaScript and TypeScript. Deno source code is at github.com/denoland/deno, written in TypeScript/Rust, and licensed under MIT.

Regional edge function invocations

Execute an Edge Function in a region close to your database. This feature is generally available and fully available on self-hosted deployments.

Deno edge functions

Globally distributed TypeScript functions to execute custom business logic. This feature is generally available and fully available on self-hosted deployments.

NPM compatibility for edge functions

Edge functions natively support NPM modules and Node built-in APIs.

Edge Functions new environment variables

Supabase adds two new environment variables to Edge Functions: SUPABASE_PUBLISHABLE_KEYS and SUPABASE_SECRET_KEYS, alongside legacy SUPABASE_ANON_KEY and SUPABASE_SERVICE_ROLE_KEY. The new variables hold JSON objects keyed by name instead of plain strings.

Reading named secret keys from Edge Functions environment

To read a named secret key from Edge Functions, parse the SUPABASE_SECRET_KEYS JSON object and access the key by its name. For example: const secretKey = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)['default']. Multiple named keys are stored in the same object, each under its own name.

Edge Functions must use apikey header only

Send publishable and secret keys on the apikey header only in Edge Functions. If the key is also passed on the Authorization Bearer header, the platform tries to parse it as a JWT and rejects the request with 'Invalid JWT'. Set verify_jwt = false in the function configuration.

@supabase/server SDK for Edge Functions

The @supabase/server SDK removes boilerplate from Edge Functions by handling key reading from environment, parsing Authorization headers, and initializing user-scoped and admin clients. It is the recommended approach for new functions. Use auth: 'user' for functions called by clients and auth: 'secret' for functions called by backends.

@supabase/server withSupabase auth modes

The withSupabase wrapper accepts auth modes: 'user' validates the user's session JWT and provides ctx.supabase scoped to Row Level Security; 'secret' validates the secret key and provides ctx.supabaseAdmin bypassing Row Level Security. Use auth: 'secret:billing' or auth: 'publishable:web' to validate specific named keys.

@supabase/server withSupabase example with user auth

import { withSupabase } from 'npm:@supabase/server' Deno.serve( withSupabase({ auth: 'user' }, async (_req, ctx) => { // ctx.supabase is scoped to the authenticated user return Response.json({ email: ctx.userClaims?.email }) }) )

@supabase/server withSupabase example with secret auth

import { withSupabase } from 'npm:@supabase/server' Deno.serve( withSupabase({ auth: 'secret' }, async (_req, ctx) => { // ctx.supabaseAdmin is authenticated with a valid secret key return Response.json({ ok: true }) }) )

@supabase/server fetch handler export style

withSupabase returns a standard request handler and can be exported as a fetch handler: export default { fetch: withSupabase({ auth: 'user' }, async (_req, ctx) => { return Response.json({ email: ctx.userClaims?.email }) }) }. The fetch style is portable across Edge Functions, Cloudflare Workers, and Bun.

Test Edge Functions using Deno native tools

Edge Functions are powered by Deno, which provides native testing tools. The Supabase CLI extends this functionality with additional capabilities for testing Edge Functions.

Edge Functions errors troubleshooting table

Symptom: Edge Function 401/404/500/503/504/546; CPU/memory/wall-clock limit hit; won't deploy; boot error; WebSocket drop; esm.sh import fails. Layer: Edge Functions → function_edge_logs, function_logs. Troubleshooting guides: 401; 500; 503 boot; 504; 546 resource limit; Shutdown reasons; Deploy fails; esm.sh import.

Gzip-compressed Edge Function log receiver example

Example Edge Function to receive gzip-compressed logs using Node-compatible built-in APIs: ```ts import { gunzipSync } from 'node:zlib' Deno.serve(async (req) => { try { const contentEncoding = req.headers.get('content-encoding') if (contentEncoding !== 'gzip') { return new Response('Request body is not gzip compressed', { status: 400 }) } const compressedBody = await req.arrayBuffer() const decompressedBody = gunzipSync(new Uint8Array(compressedBody)) const data = JSON.parse(new TextDecoder().decode(decompressedBody)) console.log(`Received: ${data.length} logs.`) return new Response('ok', { headers: { 'Content-Type': 'text/plain' } }) } catch (error) { console.error('Error:', error) return new Response('Error processing request', { status: 500 }) } }) ```

Uncompressed Edge Function log receiver example

Example Edge Function to receive uncompressed logs. Create with `supabase functions new log-receiver`, update the function body, and deploy with `supabase functions deploy log-receiver --project-ref [PROJECT REF]`. Function code: ```ts import 'npm:@supabase/functions-js/edge-runtime.d.ts' Deno.serve(async (req) => { const data = await req.json() console.log(`Received ${data.length} logs, first log:\n ${JSON.stringify(data[0])}`) return new Response(JSON.stringify({ message: 'ok' }), { headers: { 'Content-Type': 'application/json' }, }) }) ``` Configure the drain with Gzip disabled, URL set to `https://[PROJECT REF].supabase.co/functions/v1/log-receiver`, and header `Authorization: Bearer [PUBLISHABLE KEY]`.

Edge Function as log drain feedback loop pitfall

Deploying an Edge Function as a log drain target will create a feedback loop—each drain event generates a new Edge Function log, which triggers another drain event. The batching behavior limits how fast this escalates, but it will run continuously.

Edge Function log message length limit

Edge Function log messages have a maximum length of 10,000 characters. Messages longer than this will be truncated.

Edge Functions report charts and metrics

The Edge Functions report includes: Total Edge Function Invocations (function response codes and error rates, shows function reliability and error patterns), Edge Function Execution Status Codes (function response codes and error rates, shows function reliability and error patterns), Edge Function Execution Time (average function duration and performance, shows performance optimization opportunities), Edge Function Invocations by Region (geographic distribution of function calls, shows global usage patterns and latency optimization).

Project permissions table by role - Edge Functions

Edge Functions permissions by role: Update, Delete: Owner, Admin, and Developer. View, List: Owner, Admin, Developer, and Read-Only.

Edge Function Invocations pricing model

Edge Function Invocations are billed using Package pricing, with each package representing 1 million invocations. If usage falls between two packages, you are billed for the next whole package.

Edge Function Invocations billing step example

Billing steps in 1 million invocation packages: 999,999 invocations = 1 package; 1,000,000 invocations = 1 package; 1,000,001 invocations = 2 packages; 1,500,000 invocations = 2 packages.

Edge Function Invocations invoice line item

Usage is shown as 'Function Invocations' on your invoice.

View Edge Function Invocations usage

Edge Function Invocations usage can be viewed on the organization's usage page at /dashboard/org/_/usage. The page shows usage of all projects by default. You can select a specific project from a dropdown and choose a different time period. The Edge Function Invocations section displays the number of invocations your projects have had during the selected time period.

Edge Function Invocations billing

You are charged for the number of times your functions get invoked, regardless of the response status code. Preflight (OPTIONS) requests are not billed.

Edge Functions egress definition and example

Edge Functions egress is data sent to the client when executing Edge Functions. Example: when a user completes a checkout process in an online shop and the client application triggers an Edge Function to process the payment, the confirmation response sent back to the client contributes to Edge Functions Egress.

Network restrictions impact on Edge Functions database access

With network restrictions applied, Edge Functions lose direct access to the database. To connect to the database from Edge Functions when network restrictions are in place, use supabase-js instead.

Reading messages from queue with Edge Function

To read messages from a Supabase Queue in an Edge Function, use the pgmq_public schema and call the 'read' RPC function with parameters: queue_name (string), sleep_seconds (number), and n (number for how many messages to read). Returns messages array or error object.

Triggering Edge Function queue processing

Edge Functions that consume queue messages can be scheduled to run periodically using Supabase Cron to process messages at regular intervals, or invoked on demand using supabase.functions.invoke().

Edge Function queue consumption example

Example Edge Function that reads 5 messages from a queue, processes them with custom logic, and deletes them on success: ```tsx import 'jsr:@supabase/functions-js/edge-runtime.d.ts' import { createClient } from 'npm:@supabase/supabase-js@2' const supabaseUrl = 'supabaseURL' const supabaseKey = 'supabaseKey' const supabase = createClient(supabaseUrl, supabaseKey) const queueName = 'your_queue_name' interface QueueMessage { msg_id: bigint read_ct: number vt: string enqueued_at: string message: any } async function processMessage(message: QueueMessage) { const { error: deleteError } = await supabase.schema('pgmq_public').rpc('delete', { queue_name: queueName, msg_id: message.msg_id, }) if (deleteError) { console.error(`Failed to delete message ${message.msg_id}:`, deleteError) } else { console.log(`Message ${message.msg_id} deleted from queue`) } } Deno.serve(async (req) => { const { data: messages, error } = await supabase.schema('pgmq_public').rpc('read', { queue_name: queueName, sleep_seconds: 0, n: 5, }) if (error) { console.error(`Error reading from ${queueName} queue:`, error) return new Response(JSON.stringify({ error: error.message }), { status: 500, headers: { 'Content-Type': 'application/json' }, }) } if (!messages || messages.length === 0) { console.log('No messages in workflow_messages queue') return new Response(JSON.stringify({ message: 'No messages in queue' }), { status: 200, headers: { 'Content-Type': 'application/json' }, }) } console.log(`Found ${messages.length} messages to process`) for (const message of messages) { try { await processMessage(message as QueueMessage) } catch (error) { console.error(`Error processing message ${message.msg_id}:`, error) } } return new Response( JSON.stringify({ message: `Processing ${messages.length} messages in background`, count: messages.length, }), { status: 200, headers: { 'Content-Type': 'application/json' }, } ) }) ```

Edge Function queue message processing pattern

When an Edge Function processes queue messages, if processMessage throws an error, the message remains in the queue and will be read again on the next Edge Function execution. This enables retry logic for failed message processing.

Deleting messages from queue with Edge Function

To delete a message from a Supabase Queue, use the pgmq_public schema and call the 'delete' RPC function with parameters: queue_name (string) and msg_id (bigint). Messages should be deleted after successful processing.

Deno Edge Functions npm supply chain security

If using @supabase/supabase-js (or any npm: specifier) from Deno in a Supabase Edge Function, the npm-side minimum-release-age gate is unavailable at runtime. Mitigations: (1) pin to exact versions in import map / deno.json; avoid floating tags like latest. (2) Vendor critical dependencies with deno vendor and commit the vendored output to freeze the dep at a known-good snapshot and remove the runtime fetch. (3) Use --lock and --lock-write in CI to fail any build pulling unexpected content. (4) Stay current on Deno; newer versions land more supply-chain features (lockfile integrity, npm: provenance verification). Track the Deno release notes. Contact the Supabase Functions team if your security posture depends on a feature only in a newer Deno version.

Deploy Edge Functions

Use 'supabase functions deploy <function_name>' to deploy Edge Functions to your remote Supabase project.

Test Edge Function locally

Start the local functions server with: supabase functions serve. Then test with curl: curl --request POST 'http://localhost:54321/functions/v1/embed' --header 'Content-Type: application/json' --header 'apikey: SUP••••••EY' --data '{ "input": "hello world" }'. Replace SUPABASE_PUBLISHABLE_KEY with your project's publishable key from supabase status.

Generate text embeddings with Edge Functions

You can generate high quality text embeddings in Edge Functions using the built-in AI inference API without requiring an external API.

Create Edge Function for embeddings

Create an Edge Function using the command: supabase functions new embed. This creates a new TypeScript file called index.ts under ./supabase/functions/embed.

Example: Edge Functions error handling with instanceof

import { FunctionsFetchError, FunctionsHttpError, FunctionsRelayError } from '@supabase/supabase-js'; const { data, error } = await supabase.functions.invoke('hello'); if (error instanceof FunctionsHttpError) { console.error('Function error', await error.context.json()); } else if (error) { console.error(error); }

Edge Functions error handling

Functions errors arrive as one of three subclasses: FunctionsHttpError, FunctionsFetchError, or FunctionsRelayError. Narrow with instanceof; for FunctionsHttpError, parse the body to get the function's own error payload using await error.context.json().

Give your agent this brain