惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cisco Talos Blog
Cisco Talos Blog
V
V2EX
C
Check Point Blog
GbyAI
GbyAI
D
Docker
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
B
Blog RSS Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
Netflix TechBlog - Medium
T
Troy Hunt's Blog
博客园 - Franky
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Security Blog
Microsoft Security Blog
P
Privacy & Cybersecurity Law Blog
WordPress大学
WordPress大学
The Cloudflare Blog
S
SegmentFault 最新的问题
Latest news
Latest news
Microsoft Azure Blog
Microsoft Azure Blog
P
Proofpoint News Feed
I
InfoQ
博客园 - 【当耐特】
NISL@THU
NISL@THU
A
About on SuperTechFans
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
The Hacker News
The Hacker News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Scott Helme
Scott Helme
雷峰网
雷峰网
C
CXSECURITY Database RSS Feed - CXSecurity.com
Security Latest
Security Latest
V
Vulnerabilities – Threatpost
Security Archives - TechRepublic
Security Archives - TechRepublic
A
Arctic Wolf
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
IT之家
IT之家
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
aimingoo的专栏
aimingoo的专栏
T
Threat Research - Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
SecWiki News
SecWiki News
大猫的无限游戏
大猫的无限游戏
S
Security Affairs
The Register - Security
The Register - Security
www.infosecurity-magazine.com
www.infosecurity-magazine.com
L
LINUX DO - 热门话题
T
Tor Project blog

Supabase Blog

AI Agents Know About Supabase. They Don't Always Use It Right. Custom OIDC Providers for Supabase Auth 100,000 GitHub stars Supabase docs over SSH Navigating Regional Network Blocks Supabase Joins the Stripe Projects Developer Preview Log Drains: Now available on Pro Supabase Storage: major performance, security, and reliability updates Supabase incident on February 12, 2026 Hydra joins Supabase X / Twitter OAuth 2.0 is now available for Supabase Auth BKND joins Supabase Supabase is now an official Claude connector Supabase PrivateLink is now available Introducing: Postgres Best Practices When to use Read Replicas vs. bigger compute Introducing TRAE SOLO integration with Supabase Supabase Security Retro: 2025 Sync Stripe Data to Your Supabase Database in One Click Building ChatGPT Apps with Supabase Edge Functions and mcp-use Own Your Observability: Supabase Metrics API Introducing iceberg-js: A JavaScript Client for Apache Iceberg Introducing Supabase for Platforms Adding Async Streaming to Postgres Foreign Data Wrappers Build "Sign in with Your App" using Supabase Auth Introducing Seven New Email Templates for Supabase Auth The new Supabase power for Kiro Introducing Supabase ETL Introducing Analytics Buckets Introducing Vector Buckets Snap, Inc. Launches Snap Cloud, Powered by Supabase Triplit joins Supabase Supabase Series E 1000 Y Combinator Founders Choose Supabase gm 👋 web3, welcome aboard to Sign in with Web3 (Solana, Ethereum) Announcing the Supabase Remote MCP Server Enterprise speed, enterprise standards with Bolt Cloud + Supabase PostgREST 13 Lovable Cloud + Supabase: The Default Platform for AI Builders Processing large jobs with Edge Functions, Cron, and Queues Defense in Depth for MCP Servers OrioleDB Patent: now freely available to the Postgres community Supabase Launch Week 15 Hackathon Winner Announcement The Vibe Coder's Guide to Supabase Environments Testing for Vibe Coders: From Zero to Production Confidence The Vibe Coding Master Checklist Vibe Coding: Best Practices for Prompting Supabase Auth: Build vs. Buy Top 10 Launches of Launch Week 15 Supabase Launch Week 15 Hackathon Storage: 10x Larger Uploads, 3x Cheaper Cached Egress, and 2x Egress Quota Persistent Storage and 97% Faster Cold Starts for Edge Functions Algolia Connector for Supabase New Observability Features in Supabase Improved Security Controls and A New Home for Security Introducing Branching 2.0 Stripe-To-Postgres Sync Engine as standalone Library Supabase Analytics Buckets with Iceberg Support Create a Supabase backend using Figma Make Introducing JWT Signing Keys Supabase UI: Platform Kit Build a Personalized AI Assistant with Postgres Announcing Multigres: Vitess for Postgres Building on open table formats Open Data Standards: Postgres, OTel, and Iceberg Simplifying back-end complexity with Supabase Data APIs PostgreSQL Event Triggers without superuser access Top 10 Launches of Launch Week 14 Supabase MCP Server Data API Routes to Nearest Read Replica Declarative Schemas for Simpler Database Management Realtime: Broadcast from Database Keeping Tabs on What's New in Supabase Studio Edge Functions: Deploy from the Dashboard + Deno 2.1 Automatic Embeddings in Postgres Introducing the Supabase UI Library Supabase Auth: Bring Your Own Clerk Postgres Language Server: Initial Release Migrating from Fauna to Supabase Migrating from the MongoDB Data API to Supabase Dedicated Poolers Postgres as a Graph Database: (Ab)using pgRouting AI Hackathon at Y Combinator Calendars in Postgres using Foreign Data Wrappers Supabase Launch Week 13 Hackathon Winners How to Hack the Base! Running Durable Workflows in Postgres using DBOS database.build v2: Bring-your-own-LLM Restore to a New Project Hack the Base! with Supabase Top 10 Launches of Launch Week 13 Supabase Queues High Performance Disk Supabase Cron Supabase CLI v2: Config as Code Supabase AI Assistant v2 OrioleDB Public Alpha Executing Dynamic JavaScript Code on Supabase with Edge Functions ClickHouse Partnership, improved Postgres Replication, and Disk Management Live Share: Connect to in-browser PGlite with any Postgres client
Supabase Edge Functions: Introducing Background Tasks, Ephemeral Storage, and WebSockets
Lakshan Perera, Nyannyacha · 2024-12-03 · via Supabase Blog

Supabase Edge Functions: Introducing Background Tasks, Ephemeral Storage, and WebSockets

We are excited to announce three long-awaited features: Background Tasks, Ephemeral File Storage, and WebSockets.

Starting today, you can use these features in any project. Let's explore what exciting things you can build with them.

Sometimes you need a backend logic to do more than respond to a request. For example, you might want to process a batch of files and upload the results to Supabase Storage. Or read multiple entries from a database table and generate embeddings for each entry.

With the introduction of background tasks, executing these long-running workloads with Edge Functions is super easy.

We've introduced a new method called EdgeRuntime.waitUntil , which accepts a promise. This ensures that the function isn't terminated until the promise is resolved.

Free projects can run background tasks for a maximum of 150 seconds (2m 30s). If you are on a paid plan, this limit increases to 400 seconds (6m 40s). We plan to introduce more flexible limits in the coming months.

You can subscribe to notifications when the function is about to be shut down by listening to beforeunload event. Read the guide for more details on how to use background tasks.

Edge Function invocations now have access to ephemeral storage. This is useful for background tasks, as it allows you to read and write files in the /tmp directory to store intermediate results.

Check the guide on how to access ephemeral storage.

Example: Extracting a zip file and uploading its content to Supabase Storage#

Let's look at a real-world example using Background Tasks and Ephemeral Storage.

Imagine you're building a Photo Album app. You want your users to upload photos as a zip file. You would extract them in an Edge Function and upload them to storage.

One of the most straightforward ways to implement is using streams:


_35

import { ZipReaderStream } from 'https://deno.land/x/zipjs/index.js'

_35

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

_35

_35

const supabase = createClient(

_35

Deno.env.get('SUPABASE_URL'),

_35

Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')

_35

)

_35

_35

Deno.serve(async (req) => {

_35

const uploadId = crypto.randomUUID()

_35

_35

const { error } = await supabase.storage.createBucket(uploadId, {

_35

public: false,

_35

})

_35

_35

for await (const entry of await req.body.pipeThrough(new ZipReaderStream())) {

_35

// write file to Supabase Storage

_35

const { error } = await supabase.storage

_35

.from(uploadId)

_35

.upload(entry.filename, entry.readable, {})

_35

_35

console.log('uploaded', entry.filename)

_35

}

_35

_35

return new Response(

_35

JSON.stringify({

_35

uploadId,

_35

}),

_35

{

_35

headers: {

_35

'content-type': 'application/json',

_35

},

_35

}

_35

)

_35

})


If you test out the streaming version, it will run into memory limit errors when you try to upload zip files over 100MB. This is because the streaming version has to keep every file in a zip archive in memory.

We can modify it instead to write the zip file to a temporary file. Then, use a background task to extract and upload it to Supabase Storage. This way, we only read parts of the zip file to the memory.


_73

import { BlobWriter, ZipReader, ZipReaderStream } from 'https://deno.land/x/zipjs/index.js'

_73

_73

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

_73

_73

const supabase = createClient(

_73

Deno.env.get('SUPABASE_URL'),

_73

Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')

_73

)

_73

_73

let numFilesUploaded = 0

_73

_73

async function processZipFile(uploadId, filepath) {

_73

const file = await Deno.open(filepath, { read: true })

_73

const zipReader = new ZipReader(file.readable)

_73

const entries = await zipReader.getEntries()

_73

_73

await supabase.storage.createBucket(uploadId, {

_73

public: false,

_73

})

_73

_73

await Promise.all(

_73

entries.map(async (entry) => {

_73

// read file entry

_73

const blobWriter = new BlobWriter()

_73

const blob = await entry.getData(blobWriter)

_73

_73

if (entry.directory) {

_73

return

_73

}

_73

_73

// write file to Supabase Storage

_73

await supabase.storage.from(uploadId).upload(entry.filename, blob, {})

_73

_73

numFilesUploaded += 1

_73

console.log('uploaded', entry.filename)

_73

})

_73

)

_73

_73

await zipReader.close()

_73

}

_73

_73

// you can add a `beforeunload` event listener to be notified

_73

// when Function Worker is about to terminate.

_73

// use this to do any logging, save states.

_73

globalThis.addEventListener('beforeunload', (ev) => {

_73

console.log('function about to terminate: ', ev.detail.reason)

_73

console.log('number of files uploaded: ', numFilesUploaded)

_73

})

_73

_73

async function writeZipFile(filepath, stream) {

_73

await Deno.writeFile(filepath, stream)

_73

}

_73

_73

Deno.serve(async (req) => {

_73

const uploadId = crypto.randomUUID()

_73

await writeZipFile('/tmp/' + uploadId, req.body)

_73

_73

// process zip file in a background task

_73

// calling EdgeRuntime.waitUntil() would ensure

_73

// function worker wouldn't exit until the promise is completed.

_73

EdgeRuntime.waitUntil(processZipFile(uploadId, '/tmp/' + uploadId))

_73

_73

return new Response(

_73

JSON.stringify({

_73

uploadId,

_73

}),

_73

{

_73

headers: {

_73

'content-type': 'application/json',

_73

},

_73

}

_73

)

_73

})


Edge Functions now support establishing both inbound (server) and outbound (client) WebSocket connections. This enables a variety of new use cases.

Example: Building an authenticated relay to OpenAI Realtime API#

OpenAI recently introduced a Realtime API, which uses WebSockets. This is tricky to implement purely client-side because you'd need to expose your OpenAI key publicly. OpenAI recommends building a server to authenticate requests.

With our new support for WebSockets, you can easily do this in Edge Functions without standing up any infrastructure. Additionally, you can use Supabase Auth to authenticate users and protect your OpenAI usage from being abused.


_80

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

_80

_80

const supabase = createClient(

_80

Deno.env.get('SUPABASE_URL'),

_80

Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')

_80

)

_80

const OPENAI_API_KEY = Deno.env.get('OPENAI_API_KEY')

_80

_80

Deno.serve(async (req) => {

_80

const upgrade = req.headers.get('upgrade') || ''

_80

_80

if (upgrade.toLowerCase() != 'websocket') {

_80

return new Response("request isn't trying to upgrade to websocket.")

_80

}

_80

_80

// WebSocket browser clients does not support sending custom headers.

_80

// We have to use the URL query params to provide user's JWT.

_80

// Please be aware query params may be logged in some logging systems.

_80

const url = new URL(req.url)

_80

const jwt = url.searchParams.get('jwt')

_80

if (!jwt) {

_80

console.error('Auth token not provided')

_80

return new Response('Auth token not provided', { status: 403 })

_80

}

_80

const { error, data } = await supabase.auth.getUser(jwt)

_80

if (error) {

_80

console.error(error)

_80

return new Response('Invalid token provided', { status: 403 })

_80

}

_80

if (!data.user) {

_80

console.error('user is not authenticated')

_80

return new Response('User is not authenticated', { status: 403 })

_80

}

_80

_80

const { socket, response } = Deno.upgradeWebSocket(req)

_80

_80

socket.onopen = () => {

_80

// initiate an outbound WebSocket connection to OpenAI

_80

const url = 'wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01'

_80

_80

// openai-insecure-api-key isn't a problem since this code runs in an Edge Function

_80

const openaiWS = new WebSocket(url, [

_80

'realtime',

_80

`openai-insecure-api-key.${OPENAI_API_KEY}`,

_80

'openai-beta.realtime-v1',

_80

])

_80

_80

openaiWS.onopen = () => {

_80

console.log('Connected to OpenAI server.')

_80

_80

socket.onmessage = (e) => {

_80

console.log('socket message:', e.data)

_80

// only send the message if openAI ws is open

_80

if (openaiWS.readyState === 1) {

_80

openaiWS.send(e.data)

_80

} else {

_80

socket.send(

_80

JSON.stringify({

_80

type: 'error',

_80

msg: 'openAI connection not ready',

_80

})

_80

)

_80

}

_80

}

_80

}

_80

_80

openaiWS.onmessage = (e) => {

_80

console.log(e.data)

_80

socket.send(e.data)

_80

}

_80

_80

openaiWS.onerror = (e) => console.log('OpenAI error: ', e.message)

_80

openaiWS.onclose = (e) => console.log('OpenAI session closed')

_80

}

_80

_80

socket.onerror = (e) => console.log('socket errored:', e.message)

_80

socket.onclose = () => console.log('socket closed')

_80

_80

return response // 101 (Switching Protocols)

_80

})


In the past few months, we have made many performance, stability, and DX improvements to Edge Functions. While these improvements often aren't visible to the end-users, they are the foundation of the new features we are announcing today.

We have a very exciting roadmap planned for 2025. One of the main priorities is to provide customizable compute limits (memory, CPU, and execution duration). We will soon announce an update on it.

Stay tuned for the upcoming launches this week. You will see how all these upcoming pieces fit like Lego bricks to make your developer life easy.