Docs

Jobs & cron

Run durable background jobs and cron schedules in Niral. Learn delayed tasks, retry handling, persistent SQLite queues and shared PostgreSQL workers.

A durable background queue — in the framework, not a Redis cluster.

// jobs.js at the project root
export const jobs = {
  sendWelcome: async ({ email }) => {
    await mail({ to: email, subject: "Welcome!", text: "…" })
  },
}

export const schedules = [
  { cron: "0 9 * * 1", job: "weeklyDigest" },   // Mondays 9:00
]
// any server block
await enqueue("sendWelcome", { email }, { delay: 5000, maxAttempts: 5 })
  • Jobs persist in data/jobs.db — they survive restarts and deploys
  • Failures retry with exponential backoff; exhausted jobs land in a dead-letter

list you can inspect

  • One sleeping timer — zero cost on the request path
  • Scale out with niral jobs as a dedicated worker process (NIRAL_JOBS=off

on the web servers)

Shared queue across servers

SQLite is the default (one box). Running a cluster? Set NIRAL_JOBS_STORE=pg (+ NIRAL_DATABASE_URL) and the queue moves into Postgres — the same zero-dep driver, no Redis:

NIRAL_JOBS_STORE=pg
NIRAL_DATABASE_URL=postgres://user:pass@host:5432/db?sslmode=require

Now any node can enqueue() and any worker picks the job up — claimed atomically with SELECT … FOR UPDATE SKIP LOCKED so a job never runs twice. Cron fires once across the whole cluster (one node wins a Postgres advisory lock and owns the schedule; if it dies, another takes over). A job abandoned by a crashed worker is reclaimed automatically. Same jobs.js, same enqueue() — just a bigger queue. Tip: await enqueue(...) so the row is committed before your response returns.