Functions
Sometimes a query isn’t enough — you need logic that runs close to the data: a multi-step transaction, an aggregate, or a job that fires on a schedule. In ZXCV you don’t ship a server for this.
v1 generated apps have no arbitrary server code. There are no serverless or edge handler files to write. A “function” here is a declared database function that runs inside Postgres and that you invoke by name. Cron and Webhooks are just two ways to trigger one.
Functions run behind the same Data Gateway as everything else. The gateway
holds the only path to the database, so a function you declare executes
server-side under the caller’s identity and your
.policy rules — and only functions you’ve
whitelisted can be called from client code.
Declare a function
A function is ordinary Postgres. Define it in the SQL editor alongside your tables:
create function complete_todo(todo_id bigint)
returns todos
language sql
as $$
update todos
set is_complete = true
where id = todo_id
returning *;
$$;This runs in one transaction inside the database. Nothing about it lives in your app bundle.
Call it with rpc
Invoke a declared function from any SDK with rpc —
“remote procedure call.” Pass the function name and its arguments as an object:
const { data, error } = await zxcv.rpc('complete_todo', { todo_id: 1 })Like every gateway call it returns { data, error } — error is null on
success, a denied rule comes back as 403, and no rows maps to 404. Only
functions on the whitelist are reachable this way, so the anon key can’t be used
to call arbitrary SQL.
Reach for rpc when a plain from('table').select(...)
can’t express what you need — an atomic multi-row update, a computed aggregate,
or logic you want to keep in one place.
Cron — run a function on a schedule
Cron runs a declared function on a schedule, with no caller. Declare the function, then attach a schedule to it in the Functions section of the dashboard.
-- the function cron will run
create function expire_stale_carts()
returns void
language sql
as $$
delete from carts where updated_at < now() - interval '7 days';
$$;Attach a schedule (standard cron syntax) so it runs, for example, every night at 3am:
0 3 * * * -> expire_stale_cartsThe job runs server-side inside the database on the cadence you set — you don’t run or host anything.
Webhooks — map an endpoint to a function
An inbound Webhook maps a public HTTP endpoint to a declared function. When a third party (a payment provider, a form service) POSTs to the endpoint, the gateway calls your function with the request payload as its argument.
-- receives the webhook payload as jsonb
create function on_payment_received(payload jsonb)
returns void
language sql
as $$
update orders
set status = 'paid'
where id = (payload->>'order_id')::bigint;
$$;Map an endpoint to it in the Functions section of the dashboard:
POST /hooks/payments -> on_payment_receivedThe provider now calls a stable URL; the gateway routes the body into your function. As with everything else, no handler file and no server to operate.
Next steps
- Database — the tables and rules your functions run against
- Realtime — subscribe to the rows your functions change
- SDK reference — the full
rpcand query API