Durable, fast workflow engine that feels like writing normal code. Graph-based, continuation-driven execution with a Rust core and Python/Node.js 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
- ✨ 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
⚡ 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.
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"))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"));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.
docs.sayiir.dev — Full documentation with guides, tutorials, and API reference.
Getting Started Python · Node.js · Rust
Learn How It Works · Architecture · Guides · Tutorials · Examples
Reference Python API · Node.js API · Rust API · Observability & OpenTelemetry · Roadmap · Contributing
| Component | Status |
|---|---|
| Rust sayiir-core · sayiir-macros · sayiir-runtime · sayiir-persistence | |
| Python bindings | |
| Node.js bindings | |
| PostgreSQL backend | |
| Cloudflare Workers | |
| Enterprise server |
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
MIT
Stop fighting your workflow engine. Start shipping.