Vyuh Workflow Engine
Business Process Orchestration
A powerful, extensible workflow engine for Dart and Flutter applications. Build complex business processes, approval flows, and stateful automations with a clean, composable API.
Why Workflow Engine?
Visual Process Modeling
Define workflows using a fluent builder API with support for sequences, parallels, and gateways.
Human-in-the-Loop
Built-in support for user tasks, approvals, and signal-based interactions.
Persistent State
Pluggable storage adapters for reliable workflow state persistence and recovery.
Fully Extensible
Type registries for custom task executors, conditions, signals, and more.
Getting Started
Core Concepts
- Workflow — The blueprint for your business process
- Workflow Instance — A running execution of a workflow
- Workflow Descriptor — Register executors with the engine
- Tokens — Track execution position through the graph
- Data Flow — How data moves through your workflow
- Type Registries — Extend the engine with custom executors
Node Types
| Node | Purpose |
|---|---|
| Start/End | Entry and exit points |
| Task | Automated tasks |
| User Task | Human interactions |
| Signal Wait | Wait for external events |
| Gateways | Branching and merging |
Patterns & Examples
Quick Example
dart
// Create deserialization context and engine
final context = RegistryDeserializationContext(
descriptors: [DefaultWorkflowDescriptor()],
);
final engine = WorkflowEngine(
context: context,
storage: InMemoryStorage(context: context),
);
await engine.initialize();
// Define a simple approval workflow
final workflow = WorkflowBuilder('expense-approval', 'Expense Approval')
.start('begin')
.task('validate-expense', execute: (ctx) async {
return {'valid': true};
})
.userTask('manager-review',
signal: 'approval_decision',
schemaType: 'approvalTask',
assignToRole: 'managers',
storeAs: 'approvalResult')
.oneOf('decision', [
Branch.whenTrue('approvalResult.approved', then: 'process-payment'),
Branch.otherwise(then: 'notify-rejection'),
])
.task('process-payment', execute: (ctx) async {
return {'processed': true};
})
.end('completed')
.from('decision').to('notify-rejection')
.task('notify-rejection', execute: (ctx) async {
return {'notified': true};
})
.end('rejected')
.build();
// Register and start the workflow
engine.registerWorkflow(workflow);
final instance = await engine.startWorkflow(
workflowCode: workflow.code,
input: {'amount': 500, 'description': 'Conference travel'},
);