ZenZip logozenzip
Rust core · zero infrastructure190+ tests green · pre-1.0

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.

$npm create zenzipjs-app@latest my-app

or npm install zenzipjs · pre-1.0, building in the open. Phases 0–10 shipped — durable engine, agents, flow control, encryption, all chaos-tested.

app.ts
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.

BullMQ + Redisapp.queue()
Temporal clusterapp.workflow()
node-cronapp.schedule()
RabbitMQapp.emit()
LangGraphapp.agent()
Grafana setupapp.dashboard()
BullMQ + Redisapp.queue()
Temporal clusterapp.workflow()
node-cronapp.schedule()
RabbitMQapp.emit()
LangGraphapp.agent()
Grafana setupapp.dashboard()
BullMQ + Redisapp.queue()
Temporal clusterapp.workflow()
node-cronapp.schedule()
RabbitMQapp.emit()
LangGraphapp.agent()
Grafana setupapp.dashboard()
BullMQ + Redisapp.queue()
Temporal clusterapp.workflow()
node-cronapp.schedule()
RabbitMQapp.emit()
LangGraphapp.agent()
Grafana setupapp.dashboard()
BullMQ + Redisapp.queue()
Temporal clusterapp.workflow()
node-cronapp.schedule()
RabbitMQapp.emit()
LangGraphapp.agent()
Grafana setupapp.dashboard()

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.

Queues

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 more
queues.ts
const 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 });
Schedules

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 more
schedules.ts
app.schedule("daily-report", "0 9 * * *", async () => {
  await reports.generate();
});

app.schedule(
  "sync",
  { every: "30s", overlap: "skip", catchup: "runOnce" },
  async () => sync(),
);
Durability

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
import.ts
// 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.

Read the spike results
409k/s

Rust→JS handler dispatches (pipelined ×256)

14 ns

sync NAPI boundary call

209k/s

SQLite WAL job inserts (batched)

190+

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.

Full roadmap
  1. Durable queues & scheduler
  2. Durable workflow engine
  3. Events, state machines & dashboard
  4. AI agent engine
  5. Postgres multi-node
  6. Production hardening & security
  7. Express-compatible HTTP layer
  8. MCP, evals & tiered memory
  9. Flow control, fairness & scale
  10. 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.