Invoke a Supabase Edge Function
Invoke a Supabase Edge Function by name. Always POSTs; body, headers, region routing, and response parsing are per-call kwargs.
Call a deployed Edge Function. invoke is always an HTTP POST against <base_url>/<function_name> — there is no method: kwarg (see the design note). The request body, custom headers, region routing, and response decoding are all per-call kwargs.
Signature
supabase.functions.invoke(function_name,body: nil,headers: {},region: nil,response_type: :text,return_response: false)Parameters
| Name | Type | Required | Description |
|---|---|---|---|
function_name | String | Required | Name of the deployed Edge Function (e.g. "hello-world"). Must be a non-empty String — anything else raises ArgumentError before the HTTP call. |
body | Hash, Array, String, nil | Optional | Request payload. A Hash or Array is JSON-encoded and sent as application/json. A String is sent as-is with text/plain (override via headers:). nil sends no body. Any other class raises ArgumentError. |
headers | Hash | Optional | Per-invocation headers merged over the client-level defaults. Existing Content-Type set by the caller is respected (||=), NOT overwritten. |
region | String, nil | Optional | One of Supabase::Functions::Types::FunctionRegion::ALL (e.g. "us-east-1") or FunctionRegion::ANY. Validated before the HTTP call — invalid regions raise ArgumentError. nil lets the server pick (no x-region header, no forceFunctionRegion query param). |
response_type | Symbol, String | Optional | How to decode the response body. :text (default) returns a UTF-8 String. :json parses the body as JSON and returns Hash/Array/scalar (raises on invalid JSON). :binary returns an ASCII-8BIT String byte-for-byte equal to the wire body. Parsing is opt-in by the caller — Content-Type is intentionally ignored. |
return_response | Boolean | Optional | Default false. Pass true to receive the deprecated Types::Response wrapper (data + status + headers) instead of the bare body. Slated for removal — read data directly instead. |
Returns
By default (return_response: false), returns the decoded body: a Hash/Array/scalar when response_type: :json, a UTF-8 String when response_type: :text, or an ASCII-8BIT String when response_type: :binary. A nil response body comes through as nil for every response_type. When return_response: true, returns a Types::Response Struct with :data, :status, and :headers — this wrapper is deprecated and slated for removal.
Errors:
Supabase::Functions::Errors::FunctionsHttpError— raised on a non-2xx response from the function. Carriesstatusand the message from the response body's"error"field (or a default message).Supabase::Functions::Errors::FunctionsRelayError— raised when the Supabase relay layer signals failure via thex-relay-error: trueresponse header. Distinguishable fromFunctionsHttpErrorand rescued separately.
Example — JSON body, JSON response
require "supabase"
supabase = Supabase.create_client(
ENV.fetch("SUPABASE_URL"),
ENV.fetch("SUPABASE_ANON_KEY")
)
result = supabase.functions.invoke(
"hello-world",
body: { name: "Ada" },
response_type: :json
)
result # => { "message" => "Hello, Ada!" }body: { ... } is JSON-encoded and sent with Content-Type: application/json. response_type: :json parses the response body — a parse failure raises JSON::ParserError (the caller asked for JSON, so a non-JSON body is a contract violation).
Example — default text response
raw = supabase.functions.invoke("hello-world", body: { name: "Ada" })
raw # => "{\"message\":\"Hello, Ada!\"}"
raw.encoding # => #<Encoding:UTF-8>Without response_type: :json, the body comes back as a raw UTF-8 String. The Content-Type response header is ignored — parsing is always opt-in by the caller.
Example — region routing
region = Supabase::Functions::Types::FunctionRegion::US_EAST_1
supabase.functions.invoke(
"ingest-event",
body: { user_id: 42, event: "signup" },
region: region
)Passing region: sets the x-region request header AND appends forceFunctionRegion=<region> to the URL query string. Region strings are validated before any HTTP call — a typo like "us-east-99" raises ArgumentError. Pass FunctionRegion::ANY (or "any") to explicitly request no region pinning. PascalCase aliases (FunctionRegion::UsEast1) also work.
Example — custom headers (trace ID, idempotency key)
supabase.functions.invoke(
"charge-customer",
body: { customer_id: 42, amount_cents: 1999 },
headers: {
"X-Trace-Id" => SecureRandom.uuid,
"Idempotency-Key" => "charge-2026-06-12-customer-42-001"
},
response_type: :json
)Per-invocation headers are merged over the client-level defaults (including Authorization). If you set Content-Type here it is respected — invoke only fills in Content-Type when the caller hasn't set one (||=).
Example — String body (already-serialized payload)
serialized = JSON.generate({ user_id: 42 })
supabase.functions.invoke(
"ingest-prebaked",
body: serialized,
headers: { "Content-Type" => "application/json" },
response_type: :json
)A String body is sent as-is (no JSON-encoding). The default Content-Type is text/plain — override it via headers: if the wire format is something else.
Example — binary response (PDF, image, etc.)
bytes = supabase.functions.invoke(
"render-invoice",
body: { invoice_id: 4242 },
response_type: :binary
)
bytes.encoding # => #<Encoding:ASCII-8BIT>
File.binwrite("invoice-4242.pdf", bytes)response_type: :binary returns the body byte-for-byte with ASCII-8BIT (BINARY) encoding — no UTF-8 munging. The encoding choice is explicit at the call site.
Example — rescuing errors
begin
supabase.functions.invoke("hello-world", body: { name: "Ada" }, response_type: :json)
rescue Supabase::Functions::Errors::FunctionsRelayError => e
# The Supabase relay (in front of the function) errored. The function
# itself may never have executed.
warn "relay error: #{e.message} (status #{e.status})"
rescue Supabase::Functions::Errors::FunctionsHttpError => e
# Non-2xx from the function. e.message is parsed from the response
# body's "error" field when present.
warn "function returned #{e.status}: #{e.message}"
endBoth error classes inherit from Supabase::Functions::Errors::FunctionsError — rescue that to catch any Functions-API failure.
Streaming responses
Streaming responses are not supported. invoke reads the full response body into memory before returning — there is no callback, block, or IO-yielding form analogous to supabase-js's Response.body ReadableStream. The underlying Faraday session does not expose a streaming reader, and :text / :binary / :json all consume response.body whole.
If your function returns a large payload, prefer:
response_type: :binaryso the bytes are not re-encoded as UTF-8 (cheap copy, no transcoding cost).- A higher per-request timeout via the client-level
timeout:kwarg — the default is 60 seconds. - A direct Faraday connection injected via
http_client:if you really need streaming semantics — you can configure the adapter to handle large responses outsideinvoke. See the Edge Functions README for the injection pattern.
If full streaming support lands, this section will be updated.
No `method:` or `query:` kwarg
invoke is always a POST, and the only query-string consumer is region routing (handled internally via forceFunctionRegion). Other design choices worth knowing: region is validated before the HTTP call (raises ArgumentError on typos rather than warning-and-coercing); a caller-provided Content-Type is respected via ||= instead of being overwritten; x-relay-error is read case-insensitively per RFC 7230; and response_type: :json raises on invalid JSON (a contract violation) rather than silently falling back to the raw String.