Sayiir
Durable, fast workflow engine that feels like writing normal code. Graph-based, continuation-driven execution with a Rust core and Python / Node.js / Cloudflare Workers bindings — no DSL, no replay, workflows from your plain code.
Sayiir is under active development. Core functionality works. We welcome contributors, maintainers, and sponsors.
- 🦀 Rust core — High-performance, memory-safe workflow engine
- 🛡 Durable — Automatic checkpointing & crash recovery with pluggable persistence
- 🧰 Multi-language — Type-safe Python, TypeScript, and Rust bindings
- ☁️ Runs on the edge — First-class Cloudflare Workers runtime with D1 persistence, checkpoint-and-exit execution, and cron-driven resume
- ✨ Built for developers — Low learning curve; native language idioms, async code you already know, no DSL. No separate server or infra to deploy; get up and running in minutes. Enterprise server in active development for when you need one
- ⏸ Workflow control — Cancel, pause, and resume running workflow instances
- 👁 Observability — Built-in OpenTelemetry tracing and logging for full workflow visibility
Why Sayiir?
⚡ No replay overhead. Resume from the last checkpoint, not from the beginning of your workflow history. JSON by default, swap to zero-copy rkyv or any binary format via the pluggable codec abstraction.
🔒 No determinism constraints. Continuation-based execution means your code can call any API, use any library — no purity rules, no sandboxing.
✍ Minimal learning curve. Familiar language patterns with sensible defaults that get out of your way. No DSL, no YAML — just code.
🐍 Python
from sayiir import task, Flow, run_workflow
@task
def fetch_user(user_id: int) -> dict:
return {"id": user_id, "name": "Alice"}
@task
def send_email(user: dict) -> str:
return f"Sent welcome to {user['name']}"
workflow = Flow("welcome").then(fetch_user).then(send_email).build()
# Quick run — no persistence
result = run_workflow(workflow, 42)
# Or plug in a durable backend for crash recovery
from sayiir import run_durable_workflow, PostgresBackend
instance_id = f"welcome-{user_id}"
status = run_durable_workflow(workflow, instance_id, 42, backend=PostgresBackend("postgresql://localhost/sayiir"))
🦀 Rust
use sayiir_runtime::prelude::*;
#[task(timeout = "30s", retries = 3)]
async fn fetch_user(id: UserId) -> Result<User, BoxError> {
db.get_user(id).await
}
#[task]
async fn send_email(user: User) -> Result<(), BoxError> {
email_service.send_welcome(&user).await
}
// Compose — workflow! auto-registers all tasks
let workflow = workflow! {
name: "welcome",
steps: [fetch_user, send_email]
}
.unwrap();
// Quick run — no persistence
workflow.run_once(user_id).await?;
// Or plug in a durable backend for crash recovery
let runner = CheckpointingRunner::new(PostgresBackend::connect("postgres://...").await?);
let instance_id = format!("welcome-{user_id}");
runner.run(&workflow, &instance_id, user_id).await?;
import { task, flow, runWorkflow } from "sayiir";
const fetchUser = task("fetch-user", (id: number) => {
return { id, name: "Alice" };
});
const sendEmail = task("send-email", (user: { id: number; name: string }) => {
return `Sent welcome to ${user.name}`;
});
const workflow = flow<number>("welcome")
.then(fetchUser)
.then(sendEmail)
.build();
// Quick run — no persistence
const result = await runWorkflow(workflow, 42);
// Or plug in a durable backend for crash recovery
import { runDurableWorkflow, PostgresBackend } from "sayiir";
const instanceId = `welcome-${42}`;
const status = runDurableWorkflow(workflow, instanceId, 42, PostgresBackend.connect("postgresql://localhost/sayiir"));
☁️ Cloudflare Workers
import { task, flow, Engine } from "@sayiir/cloudflare";
const fetchUser = task("fetch-user", async (id: number) => {
const res = await fetch(`https://api.example.com/users/${id}`);
return res.json() as Promise<{ id: number; name: string }>;
});
const sendEmail = task("send-email", async (user: { id: number; name: string }) => {
return `Sent welcome to ${user.name}`;
});
const onboarding = flow<number>("onboarding").then(fetchUser).then(sendEmail).build();
export default {
async fetch(request: Request, env: { DB: D1Database }): Promise<Response> {
const engine = await Engine.create(env.DB);
const status = await engine.run(onboarding, "onboard-42", 42);
return Response.json(status);
},
// Resume parked + evicted instances from a cron handler
async scheduled(_event: ScheduledEvent, env: { DB: D1Database }): Promise<void> {
const engine = await Engine.create(env.DB);
await engine.resumeAll(onboarding);
},
};
Rust/WASM core, D1 persistence, checkpoint-and-exit across requests, signal/delay parking with cron-driven resume. See the Cloudflare quick start.
Works with Edge & Serverless
The Rust core compiles to WASM and runs natively inside Cloudflare Workers — no sidecar, no control plane. Checkpoint-and-exit between tasks via D1, park on signals or delays, resume on cron. See the rag-agent-cf example.
When to Use Sayiir
Sayiir is a full-featured, embeddable workflow engine — branching, loops, fork/join, signals, cancel, pause, resume, retries, timeouts — that lives inside your application as a library, not beside it as a platform.
Sayiir shines when you:
- Need durable workflows (order sagas, onboarding flows, ETL, data pipelines) without deploying separate infrastructure
- Want
cargo add/pip install/npm installand a working workflow engine in minutes, not days - Already have a Postgres (or just want in-memory for dev) and don't want to manage a separate cluster
- Value a low learning curve — write normal async code, add
@task, ship to production
Sayiir isn't trying to replace major workflow platforms. But for many use cases, those platforms add significant infrastructure overhead and complexity that feels like overkill. Sayiir gives you real durability and covers most workflow composition and execution scenarios with less ceremony.
Documentation
docs.sayiir.dev — Full documentation with guides, tutorials, and API reference.
Getting Started Python · Node.js · Rust · Cloudflare Workers
Learn How It Works · Architecture · Guides · Tutorials · Examples
Reference Python API · Node.js API · Rust API · Observability & OpenTelemetry · Roadmap · Contributing
Status
| Component | Status |
|---|---|
| Rust sayiir-core · sayiir-macros · sayiir-runtime · sayiir-persistence | |
| Python bindings | |
| Node.js bindings | |
| PostgreSQL backend | |
| Cloudflare Workers + D1 | @sayiir/cloudflare |
| Enterprise server |
Community
We're looking for contributors, maintainers, sponsors, and early adopters.
GitHub Issues — Bugs and feature requests · PRs welcome — check good first issue labels · CONTRIBUTING.md
License
MIT
Stop fighting your workflow engine. Start shipping.