Refluxo 🔀⚙️🔁🛠️
A stateless, snapshot‑based, and serverless‑ready workflow engine for JavaScript.
Refluxo is a lightweight engine designed for modern distributed environments. Unlike traditional engines that "run" a process, Refluxo transitions states. It takes a snapshot, processes a step, and returns a new snapshot. This makes it the perfect backbone for "Human-in-the-loop" systems, long-running processes, and serverless architectures.
"Build your own n8n or Zapier-like automation platform with ease."
✨ Features
🌐 Runs anywhere
Refluxo is isomorphic. It runs wherever JavaScript runs:
- Serverless: Designed to run on AWS Lambda, Cloudflare Workers, Vercel, etc. No background processes required.
- Runtime: Node.js, Bun, Deno.
- Browser: React, Vue, Svelte, or vanilla JS.
📸 Snapshot-Based
Every execution step is serializable. Pause a flow, save it to a database, and resume it days later.
🛡️ Validation & Strict Schemasype Safety
Refluxo supports any validation library that implements Standard Schema. You can use the popular Zod, Valibot for a small bundle size, TypeBox or ArkType for better peformance, or any other.
If you store your schema outside code, like in a database, you can write a logic to convert it to a Standard Schema object, for a example, read the docs
🧠 Powerful Expressions
Uses JEXL to allow dynamic data mapping similar to n8n.
⏸ Human-in-the-loop
Built-in support for external triggers and manual approvals via externalPayload.
🔁 Smart Retries
Define dynamic retry policies (fixed or exponential backoff) using expressions.
📦 Installation
pnpm add refluxo-engine💡 Usage Examples
🔧 1. Defining Node Executors
Executors are pure logic. They receive resolved data and return an output.
import { NodeDefinition } from 'refluxo-engine';
import * as v from 'valibot'; // or any other
const httpRequest: NodeDefinition = {
input: v.object({
url: v.pipe(v.string(), v.url())
}),
async executor(data, context) {
const response = await fetch(data.url);
const json = await response.json();
return { data: json };
},
};🏗️ 2. Workflow Definition
Workflows are plain JSON objects, making them easy to store and fetch from a frontend or database.
const workflow = {
nodes: [
{ id: 'start', type: 'http_request', data: { url: 'https://api.example.com/data' } },
data: { check: '{{ nodes.start.last.data.status === "ok" }}' }
],
edges: [
{ source: 'start', target: 'check_status' },
{ source: 'check_status', target: 'notify_node', sourceHandle: 'true' }
]
};⏸ 3. Pause & Resume (Human-in-the-loop)
You can pause execution to wait for an event or manual approval.
// In your executor
async executor(data, context, externalPayload) {
if (!externalPayload) {
return { data: {}, __pause: true }; // Engine will stop here
}
return { data: externalPayload }; // Resumes with the payload
}
// Executing
const engine = new WorkflowEngine({ workflow, nodeDefinitions });
let snapshot = await engine.execute({ initialNodeId: 'start' });
// ... later, when the user approves ...
snapshot = await engine.execute({
snapshot,
externalPayload: { approvedBy: 'admin_id' }
});🔄 Smart Retry Policies
Retries can be static or dynamic, driven by expressions.
const apiNode = {
type: 'api_call',
retryPolicy: {
maxAttempts: 'nodes.config.last.data.retryCount',
interval: 5000,
backoff: 'exponential'
},
// ...
};🚀 Why Refluxo?
- Stateless by Design: No need for a persistent event loop. The state is in your database, not in memory.
- Highly Extensible: Replace the Expression Engine or the Validation logic easily.
- Traceable: Metadata tracks totalExecutionTime, attempts, and every node output, making debugging a breeze.
- Developer Friendly: Built with TypeScript for full type safety.
📝 Use Cases
- Automation Platforms: Build a custom Zapier/n8n for your niche.
- Approval Workflows: Systems that require human intervention (e.g., Expense approval).
- Scheduled Tasks: Flows that wait for a specific date or time to continue.
- Complex Orchestration: Microservices coordination with automatic retries.