Edge Functions
Edge Functions are small pieces of server-side code (written in TypeScript and run on Deno) that you deploy to Supabase and call by name. Reach for one whenever logic has to run on a trusted server you control rather than inside the app — calling a paid API with a secret key, sending email, or charging a card. “Edge” means each function runs in many regions close to your users, so calls stay fast.
The supabase-functions module is the Kotlin side of that: it invokes a function
by name, sends a request body, and parses the JSON it sends back into your own
Kotlin types. You start, as always, by building a feature client from your
SupabaseClient.
val functions = createFunctionsClient(client)Typed invoke
A typed invoke means you send and receive your own @Serializable data classes
instead of hand-writing raw JSON strings. You describe the shape of the request
and the response once, and the library handles the conversion both ways. The call
returns a SupabaseResult, so you branch on success and failure exactly like
every other call in the library — see Results & Errors.
@Serializable data class HelloRequest(val name: String)
@Serializable data class HelloResponse(val message: String)
val result: SupabaseResult<HelloResponse> =
functions.invokeTyped<HelloRequest, HelloResponse>(
functionName = "hello-world",
request = HelloRequest(name = "Ada"),
)
result.onSuccess { println(it.message) }Variants
There are a few flavours of invoke depending on what you send and what you want back. Pick the row that matches your case:
| Method | Body | Returns |
|---|---|---|
invokeTyped<Req, Resp>(functionName, request, …) | @Serializable Req | Resp |
invokeTyped<Resp>(functionName, body?, …) | JSON String? | Resp |
invokeWithBodyTyped<Resp>(functionName, body, contentType, …) | ByteArray (raw bytes) | Resp |
invokeUnit(functionName, body?, …) | JSON String? | Unit (fire-and-forget) |
invoke(functionName, body?, headers, region?) | JSON String? | raw String |
A couple of those terms are worth unpacking. Fire-and-forget (invokeUnit) means
you call the function but don’t care about the response body — you only need to know
it succeeded, as when triggering a background job. The plain invoke hands you the
response as a raw String, which is useful when the function returns something that
isn’t JSON, or when you’d rather parse it yourself.
Regions
By default Supabase picks a region for you. If a call is latency-sensitive you can pin it to a specific region so it always runs there:
functions.invokeTyped<HelloResponse>(
functionName = "hello-world",
region = FunctionRegion.US_EAST_1,
)FunctionRegion covers every Supabase edge region: ANY (let Supabase choose),
US_EAST_1, US_WEST_1, US_WEST_2, CA_CENTRAL_1, SA_EAST_1, EU_WEST_1,
EU_WEST_2, EU_WEST_3, EU_CENTRAL_1, AP_SOUTH_1, AP_SOUTHEAST_1,
AP_SOUTHEAST_2, AP_NORTHEAST_1, AP_NORTHEAST_2. Leaving region unset (or
using ANY) lets Supabase route to the nearest healthy region.
Every invoke accepts a headers: Map<String, String> — handy for forwarding a
user’s access token so the function runs under their RLS context. RLS context
means the function executes as the signed-in user, so your Row Level Security
rules apply to whatever it reads or writes on their behalf.