In-app queue · BullMQ / Agenda
Redis-backed queue plus a worker. Needs Redis ops. Repeats stack on every restart. Schedule lives in code and in Redis.
Today, “I need a scheduled job” has three answers — none of them give you the whole picture.
In-app queue · BullMQ / Agenda
Redis-backed queue plus a worker. Needs Redis ops. Repeats stack on every restart. Schedule lives in code and in Redis.
In-process · node-cron / cron
Stops the moment the process exits. Each replica fires it — N pods → N runs. No audit log, no retries, no concurrency guard.
Host scheduler · crontab + systemd + k8s
Per-machine install. ssh-edit drift across hosts. No who-changed-what audit. Silent failures — did it actually run?
Whichever you pick, you can’t answer: “Is this running anywhere right now? Who changed the schedule? Did the last run succeed?”
Cronix puts the schedule next to the handler. Your code is the truth. git log is your audit log.
import { createCron } from "@awbx/cronix-sdk";import { Hono } from "hono";
const cron = createCron({ app: "billing-service", baseUrl: "https://billing.example.com", secret: process.env.CRON_SECRET!,});
cron.register({ name: "reconcile-payments", schedule: "*/15 * * * *", // ← lives next to the handler handler: async (ctx) => { await reconcilePayments(); return { ok: true }; },});
const app = new Hono();app.all("/.well-known/cron-manifest", (c) => cron.handle(c.req.raw));app.all("/api/v1/scheduled/:name", (c) => cron.handle(c.req.raw));Then, from your laptop or CI:
cronix apply --manifest https://billing.example.com/.well-known/cron-manifest \ --backend crontab --crontab-path /etc/crontab \ --trigger-bin /usr/local/bin/cronix --secret-ref env:CRON_SECRETReviewers see schedule changes in the same diff as the code change.
Schedule lives with the handler
The cron expression is a property of the function it triggers, not a row in some other system. Reviewers see the schedule change in the same diff as the code change.
Your app is the source of truth
cronix reads your manifest at apply time and reconciles the host scheduler to match. Drift between declared and installed is one command away.
Native scheduler does the firing
No background process, no broker, no Redis. cron, systemd-timer, kubelet, EventBridge — whatever the host already runs — does the work.
HMAC-signed every fire
Stripe-style signatures (timestamp + sha256) on every request. Constant-time verify. Multiple secrets supported for zero-downtime rotation.
Multi-backend, one contract
crontab, systemd-timer, Kubernetes CronJob, AWS EventBridge Scheduler, Vercel Cron — same manifest, same signing contract, swap with one flag.
Polyglot from day one
TypeScript SDK + Go SDK conformance-tested against shared spec vectors. Python, Ruby, and others welcome — the protocol is the product.
brew install awbx/cronix/cronixcurl -fsSL https://raw.githubusercontent.com/awbx/cronix/main/install.sh | shgo install github.com/awbx/cronix/go/cmd/cronix@latestdocker pull awbx/cronixpnpm add @awbx/cronix-sdkFull install matrix → Install