Edge Functions Overview
Edge Functions let you run server-side TypeScript/JavaScript on AnvilBase — for webhooks you receive, custom API endpoints, scheduled work, third-party integrations, and anything that needs a secret you can’t ship to the client. They run in the Deno runtime, with each project’s functions served by their own isolated OS process that is filesystem-scoped to that project alone — see Runtime & Isolation.
Invoking a function
POST /v1/functions/<project_id>/<function_name>curl -X POST "http://localhost:39001/v1/functions/<id>/hello" \ -H "apikey: $ANON_KEY" -H "Content-Type: application/json" \ -d '{"name":"Ada"}'const { data } = await db.functions.invoke('hello', { body: { name: 'Ada' } })res = db.functions.invoke("hello", {"body": {"name": "Ada"}})What’s injected into a function
When the control plane proxies an invocation to the Deno runtime, it injects your project’s context as request headers (and strips any that the client tried to spoof). Inside the function you can read them to talk back to AnvilBase:
| Header | Value |
|---|---|
X-AnvilBase-Project-ID | the project UUID |
X-AnvilBase-URL | the control-plane base URL |
X-AnvilBase-Anon-Key | the project anon key |
X-AnvilBase-Service-Role-Key | the project service_role key |
X-AnvilBase-DB-URL | a direct Postgres connection string for the project DB |
This means a function can query the database, call the REST API, read storage, or use the secrets vault as the project, without you hard-coding credentials.
On a public (verify_jwt: false) invocation made with no credential, the
X-AnvilBase-Service-Role-Key header is withheld (anon-level context — see
Authentication below). Project secrets are
available regardless via Deno.env.get.
// supabase-functions style handlerDeno.serve(async (req) => { const projectUrl = req.headers.get('X-AnvilBase-URL')! const serviceKey = req.headers.get('X-AnvilBase-Service-Role-Key')! const projectId = req.headers.get('X-AnvilBase-Project-ID')!
// Use the REST API as the project (service_role — server-side, bypasses RLS) const r = await fetch(`${projectUrl}/v1/rest/${projectId}/todos?limit=5`, { headers: { apikey: serviceKey }, }) const todos = await r.json() return Response.json({ todos })})Authentication: verify_jwt
Each function has a verify_jwt flag, default true (secure by default):
verify_jwt: true— the caller must present a valid project credential (the project JWT or an API key inAuthorization: Beareror theapikeyheader). An invocation with no credential — or an invalid one — is rejected with401. As always, the credential must belong to this project (cross-tenant credentials get403).verify_jwt: false— the function is public: it can be invoked with no credential at all (e.g. an inbound Stripe / GitHub / third-party webhook that can’t send your API key). Do your own verification inside (signature checks, shared-secret headers, etc.).
This gate is per-function: marking one function verify_jwt: false opens
only that function. Every other function — and every other route on the
platform — still requires authentication. A credential, when supplied, is still
validated and tenant-checked even for a public function.
A public invocation gets anon-level context, never service_role
When a public function is invoked without a credential, the proxy injects
only anon-level project context — the X-AnvilBase-Service-Role-Key header
is not sent (a public webhook target must not get elevated DB access by
default). If a public function genuinely needs service_role for a privileged
DB write, store the service-role key (or any other credential) as a project
secret and read it from
Deno.env inside the function — explicitly. An authenticated invocation
receives the full context unchanged.
Isolation & limits
- One isolated process per project — each project’s functions run in their
own OS process, filesystem-scoped to
/functions/<project_id>only. A function cannot read another tenant’s source, and a crash in one project can’t take down another. Full details and pool/lifecycle behavior in Runtime & Isolation. - No ambient filesystem/network trust — Deno’s permission model sandboxes
each worker; functions reach the outside world over
fetch. - Function code size is capped (on the order of 10 MB) and function count
is bounded by the project’s
max_edge_function_countquota (breaches return429).
See Multi-Tenancy for the platform-wide isolation model and Runtime & Isolation for the functions runtime specifically.
Where code is stored
Function metadata lives in the project database; the code body lives in object storage. The management API is the store-of-record and also syncs the code into the Deno runtime so console-deployed functions are immediately invocable. The runtime rehydrates code on a cold cache-miss via an internal endpoint you never call directly.
Next
- Writing & Deploying — author, deploy (CLI/API/console), test, and use secrets.
- Runtime & Isolation — the per-project process model, worker pool, lifecycle, and rollback hatch.