To call a Supabase Edge Function from the frontend, use supabase.functions.invoke('function-name', { body: { ... } }). The client automatically sends the user's auth token and the project's anon key. Make sure your Edge Function handles CORS with an OPTIONS preflight response. You can also call Edge Functions with a raw fetch request if you need more control over headers and request configuration.
Calling Supabase Edge Functions from Your Frontend Application
Supabase Edge Functions run server-side TypeScript code, but you invoke them from the browser like any API call. The Supabase JS client provides a functions.invoke() method that automatically handles authentication headers, making it the easiest way to call your Edge Functions. This tutorial covers the invoke method, handling different response types, error handling, CORS configuration, and using raw fetch as an alternative.
Prerequisites
- A deployed Supabase Edge Function (see how-to-use-supabase-edge-functions)
- @supabase/supabase-js installed in your frontend project
- Supabase client initialized with your project URL and anon key
- Basic understanding of async/await and HTTP requests
Step-by-step guide
Invoke an Edge Function with the Supabase client
Invoke an Edge Function with the Supabase client
The simplest way to call an Edge Function is with supabase.functions.invoke(). Pass the function name as the first argument and an options object with a body property. The client automatically adds the Authorization header with the logged-in user's JWT token and the apikey header with your project's anon key. The response is parsed as JSON by default.
1import { createClient } from '@supabase/supabase-js'23const supabase = createClient(4 'https://your-project.supabase.co',5 'your-anon-key'6)78// Basic invocation with a JSON body9const { data, error } = await supabase.functions.invoke('hello-world', {10 body: { name: 'Alice' },11})1213if (error) {14 console.error('Function error:', error.message)15} else {16 console.log('Response:', data) // { message: 'Hello Alice!' }17}Expected result: The Edge Function is called and returns a JSON response that is automatically parsed.
Pass custom headers to the Edge Function
Pass custom headers to the Edge Function
You can send additional headers alongside the automatic auth headers. This is useful for passing API keys, content type overrides, or custom metadata that your Edge Function needs. Custom headers are merged with the default headers — they do not replace them.
1const { data, error } = await supabase.functions.invoke('process-payment', {2 body: {3 amount: 2999,4 currency: 'usd',5 },6 headers: {7 'x-idempotency-key': 'unique-request-id-123',8 'x-custom-header': 'my-value',9 },10})1112if (error) {13 console.error('Payment error:', error.message)14} else {15 console.log('Payment result:', data)16}Expected result: The Edge Function receives both the automatic auth headers and your custom headers.
Handle different response types
Handle different response types
By default, functions.invoke() tries to parse the response as JSON. If your Edge Function returns a different content type (like a file or plain text), you need to handle it appropriately. Check the response content type or use the raw Response object for non-JSON responses.
1// JSON response (default behavior)2const { data: jsonData } = await supabase.functions.invoke('get-report', {3 body: { month: 'march' },4})56// For non-JSON responses, check the error7// The Supabase client may return an error if JSON parsing fails8// In that case, use fetch() directly for binary/text responses910// Alternative: Raw fetch for file downloads11const response = await fetch(12 'https://your-project.supabase.co/functions/v1/generate-pdf',13 {14 method: 'POST',15 headers: {16 Authorization: `Bearer ${(await supabase.auth.getSession()).data.session?.access_token}`,17 apikey: 'your-anon-key',18 'Content-Type': 'application/json',19 },20 body: JSON.stringify({ reportId: 42 }),21 }22)2324const blob = await response.blob()25const url = URL.createObjectURL(blob)Expected result: JSON responses are parsed automatically; non-JSON responses are handled with raw fetch.
Configure CORS in your Edge Function for browser requests
Configure CORS in your Edge Function for browser requests
Browser requests to Edge Functions require CORS headers. Unlike the Supabase REST API (which handles CORS automatically), Edge Functions need manual CORS configuration. Your function must handle OPTIONS preflight requests and include CORS headers in every response, including error responses. Without this, browsers will block the request with a CORS error.
1// supabase/functions/hello-world/index.ts2const corsHeaders = {3 'Access-Control-Allow-Origin': '*',4 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',5 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS, PUT, DELETE',6}78Deno.serve(async (req) => {9 // CRITICAL: Handle OPTIONS preflight10 if (req.method === 'OPTIONS') {11 return new Response('ok', { headers: corsHeaders })12 }1314 try {15 const { name } = await req.json()16 return new Response(17 JSON.stringify({ message: `Hello ${name}!` }),18 { headers: { ...corsHeaders, 'Content-Type': 'application/json' } }19 )20 } catch (err) {21 // CORS headers in error responses too22 return new Response(23 JSON.stringify({ error: 'Internal error' }),24 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }25 )26 }27})Expected result: Browser requests work without CORS errors because all responses include proper headers.
Handle errors and edge cases
Handle errors and edge cases
The functions.invoke() method returns an error object when the function returns a non-2xx status code or when the request fails entirely (network error, timeout). Always check for errors before using the data. For more detailed error handling, check the error's context property which may contain the HTTP status code.
1async function callEdgeFunction(payload: Record<string, unknown>) {2 try {3 const { data, error } = await supabase.functions.invoke('my-function', {4 body: payload,5 })67 if (error) {8 // Error from the Edge Function (non-2xx status)9 console.error('Function returned error:', error.message)1011 // Check if it's an auth error12 if (error.message.includes('Unauthorized') || error.message.includes('401')) {13 // Redirect to login or refresh session14 await supabase.auth.refreshSession()15 // Retry the call16 return callEdgeFunction(payload)17 }1819 throw error20 }2122 return data23 } catch (err) {24 // Network error or unexpected failure25 console.error('Failed to invoke function:', err)26 throw err27 }28}Expected result: Errors are caught and handled gracefully, with auth errors triggering a session refresh.
Complete working example
1// Complete example: Calling a Supabase Edge Function from the frontend2import { createClient } from '@supabase/supabase-js'34const supabase = createClient(5 process.env.NEXT_PUBLIC_SUPABASE_URL!,6 process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!7)89// Type-safe function invocation helper10interface FunctionPayload {11 action: string12 data: Record<string, unknown>13}1415interface FunctionResponse {16 success: boolean17 result: unknown18 error?: string19}2021async function invokeFunction(22 functionName: string,23 payload: FunctionPayload24): Promise<FunctionResponse> {25 const { data, error } = await supabase.functions.invoke<FunctionResponse>(26 functionName,27 {28 body: payload,29 headers: {30 'x-request-id': crypto.randomUUID(),31 },32 }33 )3435 if (error) {36 console.error(`Edge Function '${functionName}' error:`, error.message)37 return { success: false, result: null, error: error.message }38 }3940 return data41}4243// Usage examples:4445// 1. Simple invocation46const greeting = await invokeFunction('hello-world', {47 action: 'greet',48 data: { name: 'Alice' },49})5051// 2. Authenticated invocation (token sent automatically)52const profile = await invokeFunction('get-profile', {53 action: 'fetch',54 data: { includeStats: true },55})5657// 3. Error handling58const payment = await invokeFunction('process-payment', {59 action: 'charge',60 data: { amount: 2999, currency: 'usd' },61})6263if (!payment.success) {64 console.error('Payment failed:', payment.error)65}Common mistakes when calling an Edge Function from Frontend in Supabase
Why it's a problem: Not handling the OPTIONS preflight request in the Edge Function, causing CORS errors in the browser
How to avoid: Add an OPTIONS handler at the top of your Edge Function that returns a 200 with CORS headers. Every browser sends a preflight OPTIONS request before the actual request.
Why it's a problem: Manually setting the Authorization header in functions.invoke(), overriding the automatic auth token
How to avoid: Let the Supabase client handle the Authorization and apikey headers automatically. Only pass custom headers that your function specifically needs.
Why it's a problem: Assuming functions.invoke() will work for binary responses like file downloads
How to avoid: Use raw fetch() for non-JSON responses (files, streams, images). The invoke method is designed for JSON request-response patterns.
Why it's a problem: Not checking the error property and using data directly, which may be null
How to avoid: Always check for errors first: if (error) { handle error } else { use data }. When the function returns a non-2xx status, data may be null.
Best practices
- Use supabase.functions.invoke() for JSON-based Edge Function calls — it handles auth headers automatically
- Always handle both success and error cases when invoking Edge Functions
- Create a wrapper function with TypeScript generics for type-safe Edge Function calls
- Use raw fetch() for non-JSON responses like file downloads or streaming
- Include CORS headers in every Edge Function response, including error responses
- Add request IDs via custom headers for debugging and tracing in production
- Implement retry logic with exponential backoff for transient failures
- Keep Edge Function payloads small — pass IDs and let the function fetch data from the database
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Show me how to call a Supabase Edge Function from a React component using supabase.functions.invoke(). The function processes an order and returns a confirmation. Include TypeScript types, error handling, loading state, and a retry mechanism for failed requests.
Create a frontend utility module that wraps supabase.functions.invoke() with TypeScript generics, automatic retry on 5xx errors, request ID tracking, and structured error handling. Include example usage for calling an order processing Edge Function.
Frequently asked questions
Does functions.invoke() automatically send the user's auth token?
Yes. If the user is logged in, the Supabase client automatically includes their JWT in the Authorization header. If not logged in, only the anon key is sent via the apikey header.
Can I call an Edge Function without authentication?
Yes. Deploy the function with --no-verify-jwt (supabase functions deploy my-function --no-verify-jwt). This allows unauthenticated requests, which is necessary for public webhooks or unauthenticated APIs.
Why do I get a CORS error even though the function works with curl?
Curl does not enforce CORS — only browsers do. Your Edge Function must handle the OPTIONS preflight request and include Access-Control-Allow-Origin headers in every response. Check that error responses also include CORS headers.
What happens if the Edge Function times out?
Edge Functions have a 150-second timeout. If exceeded, the client receives a timeout error. For long-running tasks, return a task ID immediately and have the client poll a database table for the result.
Can I invoke Edge Functions from server-side code (not a browser)?
Yes. Use the same supabase.functions.invoke() method or a raw HTTP request. Server-side calls do not need CORS handling. You can also use the service role key for admin-level access.
How do I test Edge Function calls locally?
Run supabase functions serve to start the local function server. Point your frontend's Supabase URL to http://localhost:54321 and the functions will be available at http://localhost:54321/functions/v1/<name>.
Can RapidDev help build Edge Function integrations for my app?
Yes. RapidDev can architect Edge Function APIs, implement CORS handling, build type-safe client wrappers, and set up error handling patterns for your Supabase Edge Function integrations.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation