Workers that outlive a request
Persistent workers for queue processing, synchronization and periodic jobs, on an interval you control. JavaScript and TypeScript bundle from a single file; Python, Go, .NET, Rust, Java, Bun, Deno and Docker ship as a directory and are built on the server.
- Long-running processes
- The same runtimes as applications
- Live logs and memory visibility
Not bound to a request
A function is a background process, not a request handler with a timeout. Use it for queues, syncs and schedules you drive yourself.
One entry file, or a whole directory
On the default runtime the CLI bundles local imports with esbuild from a single file. Every other runtime takes the directory, packages it and builds it on the server. Secrets are environment variables either way.
Same isolation as applications
Rootless container, read-only root filesystem, dropped capabilities, hard memory limit. A worker is not a privileged citizen.
Failures are visible
Logs and memory use are in the dashboard. Exceed the hard limit and the kernel terminates the container; the restart policy retries up to five times.
Idempotency is your job
Processes restart. Claim work atomically with FOR UPDATE SKIP LOCKED and make handlers safe to run twice.
State belongs in Postgres
The container filesystem is read-only and ephemeral. Job state, cursors and checkpoints go into your database.
Write the loop you mean
Handle errors inside the loop and include a delay, otherwise a worker will happily consume a full CPU doing nothing useful. The platform will not guess an interval for you.
export default async function main() {
while (true) {
try {
await processNextBatch();
} catch (error) {
console.error(error);
}
await new Promise(resolve => setTimeout(resolve, 5000));
}
}Build the whole backend in one project
One plan, one dashboard, one command line interface. PostgreSQL, applications, functions, storage and realtime.