The agent-native backend framework for Node.js
Durable workflows, queues, schedules, and agents on a single Rust-powered runtime. No Redis. No Temporal cluster. No RabbitMQ. npm install is the entire setup.
or npm install zenzipjs · pre-1.0, building in the open. Phases 0–10 shipped — durable engine, agents, flow control, encryption, all chaos-tested.
import { zenzip } from "zenzipjs";
const app = zenzip(); // zero config — embedded SQLite WAL store
const order = app.workflow("order", async ({ step, input }) => {
const payment = await step.run("charge", () => stripe.charge(input));
await step.sleep("cooloff", "10m"); // survives restarts
const ok = await step.waitForEvent("approved", "order.approved", {
timeout: "1h",
});
await step.run("ship", () => shipping.create(payment)); // memoized forever
return { shipped: true };
});
await app.start();
await order.trigger({ orderId: "o_42" }, { idempotencyKey: "o_42" });Delete six pieces of infrastructure
Backend teams glue together a queue broker, a workflow cluster, a cron box, a message bus, and an agent framework — then operate all of it. ZenZip embeds the runtime in your process, the way SQLite replaced “install a database server.”
Scale-out later? Point the same API at Postgres. Nothing else changes.
One engine underneath everything
A queue job is a single-step run. A schedule fires onto a hidden queue. A workflow run is a job whose handler drives the step journal. An agent is a workflow with dynamic steps. One Rust engine — every feature inherits leases, retries, and recovery.
Durable workflows
Step-memoized execution: every step.run() result is journaled. Crash, deploy, or sleep for a month — runs resume exactly where they left off. No replay determinism rules.
Queues without Redis
At-least-once delivery on embedded SQLite WAL: leases, exponential backoff, priorities, delays, rate limits, batch consumers, and a dead-letter queue with requeue.
Persisted schedules
Cron + intervals with IANA timezones that survive restarts. Overlap policies, missed-tick catch-up (skip / runOnce / all), and per-fire jitter.
Rust runtime core
Timers, leases, retries, cron evaluation, and persistence run on a dedicated tokio runtime. Your event loop only ever executes your handlers.
Crash-tested recovery
SIGKILL harnesses in CI: workers killed mid-job and mid-workflow must redeliver with the attempt counted. 4× random kills mid-run still produce the correct output.
Agents are workflows
The agent engine compiles LLM loops to dynamic durable steps: tool failures retry without re-calling the model, approvals are waitForEvent gates.
BullMQ ergonomics, no Redis
Push from anywhere, process with bounded concurrency. Failures back off exponentially and dead-letter after the retry budget; requeue them with one call. Token-bucket rate limits and batch consumers built in.
Learn moreconst emails = app.queue("emails", {
concurrency: 10,
retries: 5,
backoff: { delay: "1s", maxDelay: "60s" },
rateLimit: { max: 100, per: "1m" },
});
emails.process(async (job) => {
await smtp.send(job.data); // throw = retry with backoff → DLQ
});
await emails.push({ to: "a@b.co" }, { delay: "5m", priority: 3 });Cron that survives deploys
Schedules persist in the store with their next fire time. Restart a month later and choose what happens to missed ticks: skip them, fire once, or replay all. Timezone-aware via IANA names.
Learn moreapp.schedule("daily-report", "0 9 * * *", async () => {
await reports.generate();
});
app.schedule(
"sync",
{ every: "30s", overlap: "skip", catchup: "runOnce" },
async () => sync(),
);kill -9 is a test case, not an incident
Steps are memoized in a journal. Our CI literally SIGKILLs workers mid-step, four times in a row, and asserts the run completes with the correct output and no lost steps.
Learn more// kill -9 the process anywhere in here.
// On restart: completed steps fast-forward from the journal,
// execution resumes exactly where durability last advanced.
const importer = app.workflow("import", async ({ step }) => {
const rows = await step.run("fetch", () => fetchCsv());
const parsed = await step.run("parse", () => parse(rows));
await step.all(
parsed.map((row, i) => () => step.run(`upsert-${i}`, () => db.upsert(row))),
);
return parsed.length;
});Measured, not promised
Every architecture decision was settled by a benchmark before a line of engine code was written — including the one that killed our own Rust HTTP server idea.
Rust→JS handler dispatches (pipelined ×256)
sync NAPI boundary call
SQLite WAL job inserts (batched)
tests green across Rust + TS
Every feature is shipped and tested
230+ tests green across Rust and TypeScript — including SIGKILL crash-injection and multi-node Postgres chaos suites.
- Durable queues & scheduler
- Durable workflow engine
- Events, state machines & dashboard
- AI agent engine
- Postgres multi-node
- Production hardening & security
- Express-compatible HTTP layer
- MCP, evals & tiered memory
- Flow control, fairness & scale
- npm prebuilds & launch packaging
Reliability you can kill -9
Start with the quickstart: a durable workflow, a queue, and a cron schedule in one file, backed by a single SQLite database in your project folder.