
The Fastest Code-First Workflow Automation Engine
Built with Rust + Bun for unparalleled performance
Cronflow is a powerful, lightweight, and extensible library for building, orchestrating, and running complex workflows directly in your Node.js and TypeScript applications. It's designed for developers who want the power of platforms like n8n, Zapier, or Temporal.io, but with the flexibility, version control, and expressiveness of a code-first environment.
We ran a 12-step computational heavy workflow on a Life time Free VPS from ORACLE (1vCPU, 1GB RAM). The workflow included Fibonacci calculations, 10,000+ records processed, matrix multiplication, and 3 parallel complex operations:
| Performance Metric | Traditional Tools | CronFlow Result |
|---|---|---|
| ⚡ Total Speed | 5+ seconds | 118ms |
| 🚀 Avg Speed per Step | 400ms+ | 9.8ms |
| 💾 Total Memory Peak | 500MB+ | 5.9MB |
| 🧠 Memory per Step | 4MB+ | 0.49MB |
What takes others 5+ seconds, Cronflow does in 118 milliseconds or less
Before CronFlow:
After CronFlow:
npm install cronflow"We replaced our entire n8n infrastructure with Cronflow and cut our server costs by 100% while getting 90x better performance"
While other automation engines struggle with basic webhook processing, Cronflow handles 500+ workflows per second on a single CPU core. This isn't incremental improvement, it's a complete paradigm shift that redefines what's possible in workflow automation.
Traditional engines: "Let's add more servers to handle the load" Cronflow: "Let's handle 10x more workflows on the same hardware"
npm install cronflow
Cronflow supports multiple platforms with native binaries:
The correct binary for your platform is automatically installed via optional dependencies. No compilation required!
Troubleshooting: If you encounter issues loading the native module, ensure your platform and architecture are supported. The installation will automatically download the appropriate @cronflow/[platform] package for your system.
💡 New to Cronflow? Check out our Complete Setup Guide for step-by-step instructions, including local testing, troubleshooting, and examples!
🆕 v0.9.0 Update: Cronflow now stores data in a hidden
.cronflow/directory (instead ofcronflow.dbin your project root) for a cleaner project structure. Everything is automatic - no action needed for new users! Existing users: see Migration Guide.
import { cronflow } from 'cronflow';
const workflow = cronflow.define({
id: 'hello-world',
name: 'My First Workflow'
});
workflow
.onWebhook('/webhooks/hello')
.step('greet', async (ctx) => ({ message: `Hello, ${ctx.payload.name}!` }))
.action('log', (ctx) => console.log(ctx.last.message));
cronflow.start(); // 🎉 Your workflow is live at http://localhost:3000
Test it instantly:
curl -X POST http://localhost:3000/webhooks/hello -H "Content-Type: application/json" -d '{"name":"World"}'
| Feature | Cronflow | n8n | Make.com | Zapier | Temporal |
|---|---|---|---|---|---|
| Performance | ⚡ 98% faster | 🐌 Slow | 🐌 Slow | 🐌 Slow | 🐌 Slow |
| Memory Usage | 💚 90% less | ❌ High | ❌ High | ❌ High | ❌ High |
| Type Safety | ✅ Full TypeScript | ❌ None | ❌ None | ❌ None | ⚠️ Partial |
| Code-First | ✅ Native | ❌ Visual only | ❌ Visual only | ❌ Visual only | ✅ Native |
| Testing | ✅ Comprehensive | ❌ Limited | ❌ Limited | ❌ Limited | ✅ Good |
| Deployment | ✅ Single package | ❌ Complex | ❌ Complex | ❌ Cloud only | ⚠️ Complex |
| Hot Reload | ✅ Instant | ❌ Restart required | ❌ Restart required | ❌ Not available | ⚠️ Limited |
| Error Handling | ✅ Circuit Breaker | ❌ Basic | ❌ Basic | ❌ Basic | ✅ Good |
| Monitoring | ✅ Built-in | ❌ External | ❌ External | ❌ External | ✅ Good |
Create workflow definitions with full TypeScript support:
import { cronflow } from 'cronflow';
const workflow = cronflow.define({
id: 'my-workflow',
name: 'My Workflow',
description: 'Optional workflow description'
});
Automatically create HTTP endpoints that trigger your workflows:
import { z } from 'zod';
workflow
.onWebhook('/webhooks/order', {
method: 'POST', // GET, POST, PUT, DELETE
schema: z.object({
orderId: z.string(),
amount: z.number().positive(),
customerEmail: z.string().email()
})
});
Add steps that process data and return results:
workflow
.step('validate-order', async (ctx) => {
// ctx.payload contains the webhook data
const order = await validateOrder(ctx.payload);
return { order, isValid: true };
})
.step('calculate-tax', async (ctx) => {
// ctx.last contains the previous step's result
const tax = ctx.last.order.amount * 0.08;
return { tax, total: ctx.last.order.amount + tax };
});
Execute side effects that don't return data:
workflow
.action('send-confirmation', async (ctx) => {
// Actions run in the background
await sendEmail({
to: ctx.payload.customerEmail,
subject: 'Order Confirmed',
body: `Your order ${ctx.payload.orderId} is confirmed!`
});
})
.action('log-completion', (ctx) => {
console.log('Order processed:', ctx.last);
});
Add if/else branching to your workflows:
workflow
.step('check-amount', async (ctx) => ({ amount: ctx.payload.amount }))
.if('high-value', (ctx) => ctx.last.amount > 100)
.step('require-approval', async (ctx) => {
return { needsApproval: true, amount: ctx.last.amount };
})
.action('notify-manager', async (ctx) => {
await notifyManager(`High value order: ${ctx.last.amount}`);
})
.else()
.step('auto-approve', async (ctx) => {
return { approved: true, amount: ctx.last.amount };
})
.endIf()
.step('finalize', async (ctx) => {
return { processed: true, approved: ctx.last.approved };
});
Every step and action receives a context object with:
workflow.step('example', async (ctx) => {
// ctx.payload - Original trigger data (webhook payload, etc.)
// ctx.last - Result from the previous step
// ctx.meta - Workflow metadata (id, runId, startTime, etc.)
// ctx.services - Configured services (covered in advanced features)
console.log('Workflow ID:', ctx.meta.workflowId);
console.log('Run ID:', ctx.meta.runId);
console.log('Original payload:', ctx.payload);
console.log('Previous step result:', ctx.last);
return { processed: true };
});
Launch Cronflow to handle incoming requests:
// Start on default port 3000
cronflow.start();
// Or specify custom options
cronflow.start({
port: 8080,
host: '0.0.0.0'
});
📖 View Complete API Documentation →
Run multiple steps concurrently for better performance:
workflow
.parallel([
async (ctx) => ({ email: await sendEmail(ctx.last.user) }),
async (ctx) => ({ sms: await sendSMS(ctx.last.user) }),
async (ctx) => ({ slack: await notifySlack(ctx.last.user) })
]);
Pause workflows for manual approval with timeout handling:
workflow
.humanInTheLoop({
timeout: '24h',
description: 'Manual review required',
onPause: async (ctx, token) => {
await sendApprovalRequest(ctx.payload.email, token);
},
onTimeout: async (ctx) => {
await sendTimeoutNotification(ctx.payload.email);
}
})
.step('process-approval', async (ctx) => {
if (ctx.last.timedOut) {
return { approved: false, reason: 'Timeout' };
}
return { approved: ctx.last.approved };
});
// Resume paused workflows
await cronflow.resume('approval_token_123', {
approved: true,
reason: 'Looks good!'
});
Listen to custom events from your application:
workflow
.onEvent('user.signup', {
schema: z.object({
userId: z.string(),
email: z.string().email()
})
})
.step('send-welcome', async (ctx) => {
await sendWelcomeEmail(ctx.payload.email);
return { welcomed: true };
});
// Emit events from your app
cronflow.emit('user.signup', {
userId: '123',
email: 'user@example.com'
});
Trigger workflows programmatically from your code:
// Define workflow without automatic trigger
const manualWorkflow = cronflow.define({
id: 'manual-processing'
});
manualWorkflow
.step('process-data', async (ctx) => {
return { processed: ctx.payload.data };
});
// Trigger manually with custom payload
const runId = await cronflow.trigger('manual-processing', {
data: 'custom payload',
source: 'api-call'
});
console.log('Workflow started with run ID:', runId);
Integrate with existing Express, Fastify, or other Node.js frameworks:
import express from 'express';
const app = express();
// Express.js integration
workflow.onWebhook('/api/webhook', {
app: 'express',
appInstance: app,
method: 'POST'
});
// Custom framework integration
workflow.onWebhook('/custom/webhook', {
registerRoute: (method, path, handler) => {
myFramework[method.toLowerCase()](path, handler);
}
});
app.listen(3000, async () => {
await cronflow.start(); // Start Cronflow engine
console.log('Server running on port 3000');
});
cronflow was not just designed to be a code-first alternative; it was architected from the ground up for a level of performance and efficiency that is simply not possible with traditional Node.js-based automation engines.
By leveraging a Rust Core Engine and the Bun Runtime, cronflow minimizes overhead at every layer. The result is higher throughput, lower latency, and dramatically reduced memory usage, allowing you to run more complex workflows on cheaper hardware.
What this means for you:
Traditional workflow tools like Zapier, Make.com, and n8n rely on visual drag-and-drop interfaces that seem user-friendly at first but quickly become limiting. While these tools offer hundreds of pre-built integrations, they force you into rigid templates and predefined actions. With Cronflow's code-first approach, you have infinite flexibility - you can
$ claude mcp add cronflow \
-- python -m otcore.mcp_server <graph>