Skip to content

function.yaml reference

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

function.yaml

Every key is optional. backd reads the file strictly: an unknown key or an invalid value stops startup, naming the file.

KeyDefaultMeaning
modesyncsync: the caller waits for the output. async: the caller gets a job to check later. webhook: for callbacks from other services (see Webhooks) — needs invoke set to a rule that allows anonymous callers
timeout10s (sync, webhook), 15m (async)The function is stopped after this long. At least 1s; at most 60s for sync and webhook, 24h for async
memory128MBMemory for the function’s JavaScript heap, from 32MiB to 4GiB
max_output1MiBThe largest output accepted, from 1KiB to 64MiB (15MiB for async)
concurrency10How many calls of the function may run at once on each backd instance (1–1000). With several instances, up to that many times this value run at once
rate_limitnoneCalls allowed per caller, counted across instances: {per: user | ip, limit: <n>, window: <duration>}, window from 1s to 24h
idempotencyoptionalWhether calls must send an Idempotency-Key header: optional or required
invokenoneWho may call the function (see below). Without it, only API keys may call it
adminfalsetrue gives the function full access to the realm’s data, whatever the caller may do. Keep it off unless the function needs it
internalfalsetrue removes the function’s HTTP route: _func/<name> answers 404 to everyone, like a function that doesn’t exist. Only backd and scheduled runs may call it (see Internal functions). Can’t be combined with invoke or mode: webhook
dev_onlyfalsetrue makes backd refuse to start with the function unless BACKD_DEV=true: for development helpers such as the email capture function, which must never run in production
emailfalsetrue gives the function ctx.email.send(): custom emails through the realm’s templates and delivery function, to any recipient, within the caps of email.limits. Needs email in realm.yaml; read the warning on that page first
callsnoneThe functions of the same database this one lists as callable (see Internal functions); startup rejects unknown names, cycles and chains longer than 4 functions
retrynoneTries a failed async function again: {attempts, backoff, max_backoff} (see Retrying a failed job). A single attempt unless attempts is above 1
on_completenoneFor an async function: {function, on?} queues that async function of the same database when a job of this one ends, with the outcome as its input; on narrows it to ok, failed, cancelled. See Be told when it ends
schedulenoneA cron expression: the function runs on a schedule. Needs mode: async and at least one running worker
timezoneUTCFor a scheduled function: the IANA time zone the schedule is read in, such as Europe/Madrid. Daylight saving changes are handled (documented there). Needs schedule
overlapallowFor a scheduled function: skip doesn’t run a scheduled time while the function’s previous job hasn’t finished, and records the time as a skipped job. Needs schedule
secretsnoneSecrets the function may read: NAME (its own database’s) or realm.NAME (the realm’s). Names are upper-case letters, digits and _
networknoneHosts the function may call: host or host:port, lower case, no scheme, path or wildcard. Without a list, a function can only call backd

Durations are written as in realm.yaml (30s, 15m, 1d). Sizes need a unit: B, KB, MB, GB (powers of 1000) or KiB, MiB, GiB (powers of 1024).

mode: sync
timeout: 30s
memory: 256MB
invoke: "user != nil && hasRole(user, 'staff')"
secrets: [STRIPE_KEY]
network: [api.stripe.com]

Invoke rules

invoke is an expression in the same language as access rules, with the same checks at startup. It sees only user (nil for anonymous callers) and hasRole(user, 'role'), with roles declared in realm.yaml; there is no document. Every use of user’s fields needs a guard for anonymous callers, as in rules.

invokeWho may call
noneAPI keys only
"user != nil"any signed-in user (and API keys)
"user != nil && user.email_verified"signed-in users with a verified email
"hasRole(user, 'staff')"users with the staff role
"true"anyone, including anonymous callers

invoke only applies in realms with auth: enabled. In a realm with auth: disabled, anyone who can reach backd may call its functions, as with its data.

mode: webhook requires invoke to allow anonymous callers (e.g. "true", or a rule that only checks the request itself, never user) — refused at startup otherwise. A webhook sender (Stripe, GitHub, and the like) has no backd session or API key to send; the function must be reachable without one, and prove the request is genuine itself (see Webhooks).

What is enforced today

SettingToday
timeoutEnforced: the process is stopped at the deadline, and when the caller goes away
memoryEnforced: the JavaScript heap, plus the process’s resident memory (heap + about 130 MiB)
max_outputEnforced
invoke, admin, input and output schemasEnforced
networkEnforced by the allowlist and backd egress together (see above); the third layer, network placement, is proven by a test harness and wired into the production reference — reproduce it yourself if you assemble your own deployment instead
secretsEnforced: values are encrypted at rest, admin-managed, cached briefly and delivered only as ctx.secrets (see Secrets)
concurrency, functions.max_concurrencyEnforced, per instance (see Concurrency limits)
scheduleEnforced by workers: one run per scheduled time across any number of them (see Scheduled functions)
rate_limitEnforced, shared across instances (see Rate limits)
idempotencyEnforced (see Idempotency)
mode: asyncEnforced (see Async jobs)
mode: webhookEnforced (see Webhooks)

Each function process also can’t read environment variables, files other than its own bundle, start processes or use FFI, and never shares memory with another call.

Edit this page · Last updated 08 Oct 2026