To invoke edge functions from the browser, you need to handle CORS Preflight requests.
Automatic CORS handling
The withZuvo wrapper handles CORS and preflight (OPTIONS) requests for you, so you don't add headers manually:
import { withZuvo } from 'npm:@supabase/server@^1'
export default {
fetch: withZuvo({ auth: 'user' }, async (req, ctx) => {
const { name } = await req.json()
return Response.json({ message: `Hello ${name}!` })
}),
}
Manual CORS handling
If your function doesn't use withZuvo, add the headers yourself. See the example on GitHub.
Import corsHeaders from npm:@supabase/supabase-js@^2/cors to automatically get all required headers:
import { corsHeaders } from 'npm:@supabase/supabase-js@^2/cors'
console.log(`Function "browser-with-cors" up and running!`)
export default {
fetch: async (req) => {
// Handle the CORS preflight request.
if (req.method === 'OPTIONS') {
return Response.json({ ok: true }, { headers: corsHeaders })
}
try {
const { name } = await req.json()
return Response.json({ message: `Hello ${name}!` }, { headers: corsHeaders })
} catch (error) {
return Response.json({ error: error.message }, { status: 400, headers: corsHeaders })
}
},
}
Importing from the SDK keeps your allow-list aligned with the headers the client libraries send: when you upgrade the SDK version in your function and redeploy, newly added headers are picked up with it. As of @supabase/supabase-js v2.112.3 the list includes the trace context headers (traceparent, tracestate, baggage) used by client-side tracing — functions deployed with an older version need a redeploy before browsers can call them with trace propagation enabled.
The full list, and when each header is sent:
| Header | Sent |
|---|---|
authorization | Every request (session token or API key) |
apikey | Every request |
x-client-info | Every request (SDK name and version) |
content-type | Requests with a body |
x-retry-count | Only on automatic retry attempts (postgrest-js retries failed idempotent requests by default) |
traceparent, tracestate, baggage | Only when trace propagation is explicitly enabled — never by default |
For versions before 2.95.0
If you're using @supabase/supabase-js before v2.95.0, you'll need to hardcode the CORS headers. Add a cors.ts file within a _shared folder. The list must cover every header your calling clients send — include the trace context headers if any client enables tracePropagation:
export const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers':
'authorization, x-client-info, apikey, content-type, x-retry-count, traceparent, tracestate, baggage',
}
Then import it in your function:
import { corsHeaders } from '../_shared/cors.ts'
// ... rest of your function code