Architecture Overview
ChainGraph is a source-available, flow-based programming framework that empowers developers to visually design, execute, and manage complex computational graphs. It combines a type-safe node-and-port system with a robust distributed execution engine, providing real-time synchronization through WebSockets.
Core Concepts
ChainGraph is built on four foundational concepts:
1. Nodes
Nodes are discrete computational units that perform specific tasks. Each node:
- Extends
BaseNodeCompositionalabstract class - Implements an
async execute(context: ExecutionContext)method - Has input and output ports for data flow
- Emits events during execution
- Supports batch port updates for performance
Example node structure:
@Node({
title: 'Example Node',
category: 'utilities'
})
class ExampleNode extends BaseNode {
@Input()
@String()
input: string = ''
@Output()
@Number()
output: number = 0
async execute(context: ExecutionContext): Promise<NodeExecutionResult> {
this.output = this.input.length
return {}
}
}2. Ports
Ports are typed connection points that define how data flows between nodes. The port system supports:
Primitive Types:
StringPort- Text dataNumberPort- Numeric valuesBooleanPort- True/false values
Complex Types:
ObjectPort- Structured objects with child portsArrayPort- Collections of itemsStreamPort- Asynchronous data streamsEnumPort- Restricted value setsAnyPort- Dynamic typing
Each port has:
- Configuration (
IPortConfig) defining constraints - Runtime validation via Zod schemas
- Connection tracking
- Conditional visibility rules
3. Flows
Flows are directed acyclic graphs (DAGs) composed of nodes and edges. A flow:
- Contains multiple nodes connected through ports
- Manages event propagation
- Supports serialization and cloning
- Provides validation and debugging
- Can contain parent-child node relationships
4. Execution Engine
The Execution Engine orchestrates flow execution:
- Resolves node dependencies automatically
- Supports parallel execution where possible
- Handles child execution spawning
- Tracks execution depth to prevent infinite recursion
- Provides debugging capabilities (breakpoints, step-over)
- Emits real-time events for monitoring
System Architecture
┌────────────────────────────────────────────────────────────┐
│ Frontend (React + Vite) │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ XYFlow │ │ Effector │ │ tRPC Client │ │
│ │ Canvas │ │ State Mgmt │ │ + WebSocket │ │
│ └─────────────┘ └──────────────┘ └──────────────┘ │
└────────────────────────────┬───────────────────────────────┘
│ WebSocket + tRPC
┌────────────────────────────┴───────────────────────────────┐
│ Backend (Node.js + tRPC) │
│ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐ │
│ │ tRPC Router │ │ Flow Store │ │ Execution │ │
│ │ (API Layer) │ │ (Postgres) │ │ Service │ │
│ └──────────────┘ └─────────────┘ └──────────────┘ │
└────────────────────────────┬───────────────────────────────┘
│
┌────────────────────────────┴───────────────────────────────┐
│ Distributed Execution (DBOS) │
│ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐ │
│ │ DBOS │ │ PostgreSQL │ │ Execution │ │
│ │ Workflows │ │ State DB │ │ Workers │ │
│ └──────────────┘ └─────────────┘ └──────────────┘ │
└────────────────────────────────────────────────────────────┘Project Structure
Core Packages
packages/chaingraph-types
The foundation package providing:
- Node system (
BaseNodeCompositional) - Port implementations and interfaces
- Flow management classes
- Execution engine
- Decorator system
- Type definitions and utilities
See API Reference for details.
packages/chaingraph-nodes
Pre-built node implementations:
- AI nodes (Anthropic Claude, Google Gemini)
- Data transformation nodes
- Flow control nodes
- Utility nodes
- Math and logic nodes
Over 114 ready-to-use nodes organized by category.
packages/chaingraph-trpc
Type-safe API layer providing:
- Flow CRUD operations
- Node management procedures
- Execution control endpoints
- Real-time subscriptions via WebSockets
- Debugging utilities
packages/chaingraph-executor
Backend execution engine with:
- Task queue (in-memory and DBOS-based)
- Execution service
- Recovery service for fault tolerance
- DBOS durable workflows for distributed execution
- Metrics and monitoring
packages/chaingraph-codegen
Code generation utilities for creating nodes from schemas.
Applications
apps/chaingraph-backend
Node.js backend server that:
- Hosts the tRPC API
- Manages WebSocket connections
- Stores flows and execution state
- Coordinates execution workers
apps/chaingraph-frontend
React + Vite frontend featuring:
- Visual flow editor (XYFlow-based)
- Effector-based state management
- Real-time updates
- Node property inspector
- Execution visualization
apps/chaingraph-execution-api
API service for distributed execution management.
apps/chaingraph-execution-worker
Worker processes for executing flows in a distributed system.
Key Architectural Patterns
1. Decorator-Based Configuration
Nodes use TypeScript decorators for metadata definition:
@Node({
title: 'My Node',
category: 'utilities'
})
class MyNode extends BaseNode {
@Input()
@String({ defaultValue: 'hello' })
input: string = 'hello'
}Benefits:
- Co-located logic and configuration
- Compile-time and runtime type safety
- Automatic UI generation
- Self-describing nodes
2. Compositional Architecture
BaseNodeCompositional delegates responsibilities to specialized components:
- UnifiedPortStorage - Centralized port state
- VirtualPortManager - Port hierarchy management
- OperationExecutor - Schema and port operations
- NodeEventManager - Event pub/sub
- NodeUIManager - UI state
- SystemPortManager - Flow control ports
This provides:
- Single Responsibility Principle
- Testable components
- Extensibility without modifying base class
3. Event-Driven Synchronization
Node Port Updated
↓
Node.emit(PortUpdateEvent)
↓
Flow.handleNodeEvent()
↓
Flow.emitEvent(FlowEvent)
↓
WebSocket → Frontend
↓
UI UpdatesEvent types:
- NodeEvents: Status changes, port updates, connections
- FlowEvents: Node/edge additions, port updates
- ExecutionEvents: Start, completion, failures
4. Distributed Execution
For scalability, ChainGraph supports distributed execution using DBOS:
Client → PostgreSQL (Source of Truth)
↓
DBOS Durable Workflows (Orchestration)
↓
Execution Workers (Horizontally Scalable)
↓
Automatic Recovery (DBOS Built-in)Features:
- Transactional guarantees - DBOS + PostgreSQL ensure consistency
- Fault tolerance - Automatic recovery of interrupted workflows
- Horizontal scaling - Add more worker instances
- Durable execution - Workflows survive process restarts
Data Flow: End-to-End
Creating and Executing a Flow
User creates flow in UI
- Frontend calls
trpcClient.flow.create() - Backend creates Flow object
- Stored in PostgreSQL or in-memory
- Frontend calls
User adds nodes and connects edges
- Each change triggers tRPC mutations
- Backend updates Flow
- Flow events emitted
- Updates sent to frontend via WebSocket
User clicks "Execute Flow"
- Frontend calls
trpcClient.execution.start() - ExecutionService creates ExecutionContext
- ExecutionEngine processes nodes
- Events streamed back to frontend
- Frontend calls
Node execution
- Engine calls
node.execute(context)for each node - Nodes read inputs, perform computation
- Nodes update outputs
- Events emitted for port changes
- Frontend receives updates and renders
- Engine calls
Type Safety
ChainGraph provides multiple layers of type safety:
- Compile-time: TypeScript interfaces and generics
- Runtime: Zod schema validation
- End-to-end: tRPC for client-server communication
- Serialization: SuperJSON for complex types
Performance Optimizations
- Lazy Port Instantiation - Ports created only when accessed
- Port Caching - Retrieved ports cached for reuse
- Batch Updates - Multiple port updates collected and emitted once
- Unified Storage - Centralized storage layer reduces overhead
- Event Queuing - Async event processing doesn't block execution
Technologies
Frontend
- React - UI framework
- Vite - Build tool and dev server
- XYFlow - Visual graph editor
- Effector - Reactive state management
- tRPC Client - Type-safe API calls
Backend
- Node.js - Runtime
- tRPC - API framework
- PostgreSQL - Persistent storage
- DBOS - Durable workflow orchestration
- Zod - Schema validation
- SuperJSON - Serialization
Infrastructure
- Docker - Containerization
- pnpm - Monorepo package manager
- Turbo - Build orchestration
- Vitest - Testing framework
Extending ChainGraph
Creating Custom Nodes
See the Quick Start Guide for node creation examples.
Adding Custom Port Types
Extend BasePort and implement getValue() and setValue():
class MyCustomPort extends BasePort<MyType> {
getValue(): MyType {
// Implementation
}
setValue(value: MyType): void {
// Validation and storage
}
}Custom Execution Strategies
Implement custom execution logic by extending ExecutionEngine or providing custom node execution methods.
Security Considerations
- Input Validation - All port inputs validated via Zod schemas
- Execution Sandboxing - Nodes execute in controlled contexts
- Rate Limiting - API endpoints can be rate-limited
- Authentication - tRPC supports authentication middleware
- License - BUSL-1.1 for source-available protection
Limitations & Future Work
Current limitations:
- API still evolving (breaking changes possible)
- Some advanced features under development
Planned enhancements:
- Enhanced DBOS workflow features
- PostgreSQL read replicas for scaling
- Graceful shutdown handling
- Enhanced metrics and observability
- Advanced retry and error handling strategies
Next Steps
- Explore the API Reference for detailed documentation
- Check out example nodes
- Read the Getting Started Guide
- Review Node Decorators documentation
License
ChainGraph is licensed under Business Source License 1.1 (BUSL-1.1).