Process Engine
An inside look at how ProcessFlow’s Process Engine drives workflow execution with database functions and triggers.
Process Engine Architecture
ProcessFlow’s engine is built directly into the database (PostgreSQL), using stored functions, triggers, and JSONB data to model, execute, and advance workflow instances without a separate execution service. This approach ensures that processes can run in the background without the need to have the web application open, and it allows for easy scaling and management of process instances.
High-Level Engine Overview
To visualize the core lifecycle without diving into low-level SQL, here’s a simplified flowchart:

This overview shows how tasks move from creation to completion and cycle until the workflow reaches an end node.
Core Components
- Web Application: Frontend and API Endpoint (Next.js) that start processes and displays tasks.
- Database (PostgreSQL): Stores process models, instances, flow elements, and data objects. Acts as the execution engine via PL/pgSQL.
- External Task Servers: Optional HTTP endpoints that render and collect user task input when an element is marked “Manual” or that automatically execute business logic when an element is marked “Automatic”.
Lifecycle of a Process Instance
-
create_process_instance (
PL/pgSQLfunction) is invoked with a model ID. It:- Validates a single
startNodeand at least oneendNodein the model. - Inserts a new
process_instancerow (status = Running). - Creates the first
flow_element_instancefor thestartNodeand immediately marks it Completed.
- Validates a single
-
create_next_flow_element_instance (
AFTER UPDATEtrigger) fires when any flow element instance transitions to Completed. It:- Reads the completed element’s type (
startNode,activityNode,gatewayNode,endNode, etc.). - Determines the next element ID via the corresponding element table (
start_element,activity_element,gateway_element, …). - Inserts a new
flow_element_instancefor that next element (or, if at anendNode, marks the process_instance Completed).
- Reads the completed element’s type (
-
execute_created_flow_element_instance (
AFTER INSERTtrigger) runs on newflow_element_instancerows with status = Created. It:- Skips
startNodeandendNode(automatically completed). - For gatewayNodes and endNodes, immediately marks them Completed.
- For Manual elements, sets status = Todo so it appears in the user’s Task list.
- For Automatic elements, sets status = In Progress and issues an HTTP POST to the element’s
execution_url, passing the instance ID and any JSONB data payload.
- Skips
-
complete_flow_element_instance (
PL/pgSQLfunction) is called by the app’s API when a user or external service finishes a task. It:- Inserts or updates rows in
data_object_instanceto capture output data. - Sets the corresponding
flow_element_instancerow status = Completed, recording a timestamp.
- Inserts or updates rows in
-
Cycle Continues: Completion of any element triggers step 2 again, advancing the workflow until an
endNodecompletes and the process instance status flips to Completed.
Triggers & Functions
| Trigger / Function | Purpose |
|---|---|
create_process_instance() | Validates model and seeds first element instance |
create_next_flow_element_instance (TRG) | Advances to the next flow element upon completion |
execute_created_flow_element_instance | Routes new instances to Todo or issues auto HTTP call |
complete_flow_element_instance() | Persists outputs and marks an instance Completed |
Manual vs. Automatic Execution
- Manual: Elements with
execution_mode = 'Manual'are created with status Todo. Users see them in their worklist, open them (via iframe HTTP calls), submit results, and the API invokescomplete_flow_element_instance(). - Automatic: Elements with
execution_mode = 'Automatic'go In Progress immediately. The trigger POSTS to the configuredexecution_urland relies on the callback endpoint (/api/instance/complete) to finalize.
Data Objects & Storage
- Flow Element Definitions reside in
flow_element,activity_element,gateway_element, etc., including JSONBdatafor conditional logic or input parameters. - Instance Data:
flow_element_instancetracks each element’s runtime status, timestamps, and parentprocess_instance. - Output Data:
data_object_instancestores arbitrary JSONB key/value pairs per instance, allowing downstream tasks or analytics to consume results.
With this design, ProcessFlow achieves a serverless, scalable process engine fully driven by database logic—simplifying deployment and ensuring strong data consistency.