Skip to content

Functions

Run server-side logic next to your data: sync calls, background jobs, cron schedules and webhooks, with the rules, secrets and limits that keep them safe.

Server-side functions run code you write on the server, next to your collections, for the things a client must not do or be trusted with: computing what readers may not compute themselves, making privileged changes, calling payment or email services with a secret, working on a schedule, answering another service’s callbacks. Each function is a small JavaScript or TypeScript module in your CONFIG_DIR, next to the collections it works on. backd runs it in Deno, in its own process, with only the permissions and limits it declares.

They are a core part of backd, not an add-on: a function reaches data through the same access rules as any other caller (or, when you say so, with full access), and everything around it is built in: input and output schemas, per-caller rate limits, idempotent retries, encrypted secrets, a network allowlist, background jobs, cron schedules, invocation history and console logs.

What a function looks like

A function is a folder with a function.yaml (how it runs) and an index.ts (what it does). This one prices one of the caller’s orders. It runs as the caller, so the orders’ access rules decide which orders they can read:

examples/config/workshop/main/_functions/order_total/function.yaml

# A sync function that runs as the caller: ctx.db reads with the caller's
# own access rules, so a customer can only price their own orders.
invoke: "user != nil"

examples/config/workshop/main/_functions/order_total/index.ts

// order_total: the amount a customer will be charged for one of their
// orders. The tax rule lives here, on the server, not in every client.
//
// ctx.db acts as the caller, so orders/collection.yaml decides what they may
// read: someone else's order (or one that doesn't exist) answers 404, the
// same as reading the collection directly would.
import { relay } from "../lib/relay.ts";
import type { Context, Doc } from "../lib/types.ts";

const TAX_RATE = 0.2;

export default async function handler(ctx: Context) {
  const { order_id } = ctx.input as { order_id: string };

  let order: Doc;
  try {
    order = await ctx.db("main").collection("orders").get(order_id);
  } catch (err) {
    relay(err, ctx.error);
  }
  if (order.status === "refunded") {
    throw ctx.error(409, "order_refunded", "This order was refunded");
  }

  const subtotal = order.amount as number;
  const tax = Math.round(subtotal * TAX_RATE);
  return { order_id, subtotal, tax, total: subtotal + tax };
}
curl -X POST https://api.example.com/v1/workshop/main/_func/order_total \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"order_id": "d3c9ljp8hc2g00b6s1m0"}'
# → 200 {"order_id": "d3c9ljp8hc2g00b6s1m0", "subtotal": 1000, "tax": 200, "total": 1200}

This function, and every other one quoted in this section, is in examples/config/workshop in the repository, where it is tested for real; the Cookbook walks through them all.

Which kind of function do I need?

You need to…UsePage
Decide who may read or write which documentsAccess rules — no function needed
Compute something readers can’t, or check across several documentsA sync functionWriting, Calling
Make a change no user rule may allow (a refund, a role change)A sync function with admin: trueWriting
Do work that takes more than a few seconds, or must survive the caller going awayAn async jobAsync jobs
Keep a function away from HTTP, or share a helper between functionsAn internal function, called with ctx.callInternal functions
Run something every night, hour or weekA scheduled function (schedule: on an async function)Scheduled functions
Receive a callback from Stripe, GitHub or any other serviceA webhook functionWebhooks
Call an outside API with a keyAny function, with secrets and a network allowlist

The three modes, and cron

sync (default)asyncwebhookscheduled
Who calls ita client, over HTTPa client, over HTTPanother servicea worker, on a cron schedule
The caller getsthe output, right away202 and a job to check laterthe function’s own responsenothing (there is no caller)
Runs inthe requesta background workerthe requesta background worker
Time limitup to 60 s (10 s default)up to 24 h (15 min default)up to 60 sup to 24 h
Acts asthe caller (ctx.db), or the function (ctx.admin.db)the caller who queued itnobody: it verifies the sender itselfthe function, with full access
Deliveryonceat least onceas often as the sender retriesonce per scheduled time

How it fits together

 client ── HTTP ──▶ backd ── runs the function in ──▶ executor ─▶ one Deno process per call
                     │  ▲                                              │
                     │  └────── ctx.db / ctx.admin.db, over an ◀───────┘
                     │           internal listener (short-lived credentials)
                     │
              worker (async jobs and cron schedules) ── also uses the executor
                                                               │  network: only what the function
                                                               ▼  declares, through backd egress
  • backd authenticates the caller, applies the function’s invoke rule, validates input and output, and answers.
  • The executor starts one Deno process per call and stops it at its deadline. It never sees CONFIG_DIR, MongoDB or the signing keys.
  • A worker (backd worker, or backd serve --with-worker) claims async jobs and creates the runs of scheduled functions. Async jobs and cron only happen while at least one worker runs.
  • backd egress is the only way a function reaches the outside network, and only the hosts it declares.

What backd enforces for you

  • The caller’s rules apply to ctx.db; full access needs an explicit admin: true (or is the point of a scheduled run).
  • Time, memory, output size and concurrency limits per function, and a per-caller rate limit you can declare.
  • Input and output JSON Schemas, checked on every call.
  • Idempotency keys, so a retried request doesn’t do the work twice.
  • Secrets encrypted at rest and delivered as ctx.secrets, masked in logs.
  • No environment variables, no files but the function’s bundle, no processes, and a network limited to a declared allowlist.
  • A record of every call (never its input or output) and the function’s own console output, kept for a week by default.

Where to go next

Quickstart

Your first function, from an empty directory to a call, its logs and a unit test, in about ten minutes.

Writing a function

A function’s layout, its handler, the ctx object, reading and writing data, errors and schemas.

Calling functions

Call a function over HTTP, from the JavaScript client or the CLI; the answers, limits, rate limits and idempotency.

function.yaml reference

Every function.yaml key, the invoke rules, and what backd enforces.

Async jobs

Run work in the background with mode: async, and know when it finished: polling, the JavaScript client, the CLI, and completion patterns inside the function.

Scheduled functions

Run a function on a cron schedule, with no caller: when to use it, the expression syntax, what a run can do, and how to check that it ran and finished.

Internal functions

Functions with no HTTP route, for work that only backd, scheduled runs and other functions may start.

Email

Send transactional email through any provider: you write one function, backd renders the messages.

Webhooks

Receive callbacks from other services and answer them yourself.

Secrets

Encrypted values a function may read, managed by realm administrators.

Outbound network

What a function may reach: the per-function allowlist, the egress proxy and network placement.

Build, dev and test

Bundle functions, iterate in dev mode, call them through a running backd and unit-test their logic.

Running in production

The executor, workers and egress: how to run them.

Function logs

See what your deployed functions did: invocation history, console logs, retention, and shipping logs to a long-term system.

Cookbook

Seven complete, tested recipes: a sync function as the caller, a privileged idempotent refund, a background report, a nightly cleanup, a daily digest, a payment webhook and an email delivery function for Postmark.

Files in functions

Read, write, remove and link a document’s files from a function with files(id, field), as the caller or as the function, and two recipes: a thumbnail and a counted download.

Edit this page · Last updated 08 Oct 2026