Skip to content

For Developers

Coming from a traditional coding background? This guide translates familiar programming concepts to Flow-Like’s visual workflow approach. Whether you’re a Python dev, JavaScript engineer, or seasoned systems programmer, you’ll find the mental models transfer well.

Instead of writing code like:

const result = processData(loadFile(path));
saveOutput(result, outputPath);

You build visual pipelines:

Load File ──▶ Process Data ──▶ Save Output

The flow is the program. Nodes are functions. Wires are data passing.

Programming ConceptFlow-Like Equivalent
FunctionNode
Function callConnect node output to input
VariableVariable (scoped to Board)
ParameterInput Pin (left side of node)
Return valueOutput Pin (right side of node)
Module/ClassBoard
ImportReference another Board
Main functionEvent (entry point)
LoopFor Each / While nodes
ConditionalBranch node
Try/CatchTry + Catch nodes
TypePin type
Struct/ObjectStruct type
ArrayArray type
CallbackSub-flows
Async/awaitAutomatic (execution pauses)
ThreadParallel branches

Every node is essentially a function call.

Code:

def add(a: int, b: int) -> int:
return a + b
result = add(5, 3)

Flow-Like:

┌─────────────────┐
│ Add │
│ 5 ──▶ a │
│ 3 ──▶ b │
│ sum ──▶ │ 8
└─────────────────┘

The inputs (a, b) are left-side pins. The output (sum) is a right-side pin.

Code:

value = step3(step2(step1(input)))

Flow-Like:

Input ──▶ Step 1 ──▶ Step 2 ──▶ Step 3 ──▶ Output

Data flows left-to-right through connected pins.

Variables in Flow-Like are scoped to Boards (like class attributes):

Code:

class MyProcessor:
def __init__(self):
self.counter = 0
self.results = []
def process(self, item):
self.counter += 1
self.results.append(item)

Flow-Like:

Board Variables:
├── counter: Integer (default: 0)
└── results: Array<Item>
Event: Process (item)
├──▶ Get Variable: counter
│ │
│ ▼
│ Add (counter, 1)
│ │
│ ▼
│ Set Variable: counter
└──▶ Get Variable: results
Append (results, item)
Set Variable: results
OperationNodes
ReadGet Variable
WriteSet Variable
ModifyGet → Transform → Set

Code:

if condition:
do_a()
else:
do_b()

Flow-Like:

True ──▶ Do A
Condition ──▶ Branch ─┤
False ──▶ Do B

Code:

match status:
case "pending":
handle_pending()
case "approved":
handle_approved()
case "rejected":
handle_rejected()

Flow-Like:

┌──▶ "pending" ──▶ Handle Pending
Get Status ──▶ Switch ├──▶ "approved" ──▶ Handle Approved
└──▶ "rejected" ──▶ Handle Rejected

Code:

for item in items:
process(item)

Flow-Like:

Items ──▶ For Each ──▶ Process (item) ──▶ Continue Loop
└──▶ (done) ──▶ Next Step

Code:

while condition:
do_work()
update_condition()

Flow-Like:

┌─────────────────────────────────────┐
│ │
│ ┌──────────────────┐ │
│ │ │ │
└──┤ While (condition)├──▶ Do Work ──┤
│ │ │
└────False─────────┼───────────────┘
Next Step

Code:

try:
result = risky_operation()
except SpecificError as e:
handle_error(e)
finally:
cleanup()

Flow-Like:

Try ──▶ Risky Operation ──▶ Continue
└──Catch ──▶ Handle Error
└──▶ (always runs) ──▶ Cleanup

Flow-Like is strongly typed. Define structures for complex data:

Code:

interface User {
id: string;
name: string;
email: string;
orders: Order[];
}

Flow-Like:

Struct: User
├── id: String
├── name: String
├── email: String
└── orders: Array<Order>

Code:

user.name = "Alice"
email = user.email

Flow-Like:

Set Field (user, "name", "Alice") ──▶ updated_user
Get Field (user, "email") ──▶ email_value

Code:

result1 = await step1()
result2 = await step2(result1)

Flow-Like:

Step 1 ──▶ Step 2 ──▶ Done

Execution automatically waits. No async/await syntax needed.

Code:

results = await asyncio.gather(
task1(),
task2(),
task3()
)

Flow-Like:

┌──▶ Task 1 ──┐
Start ──▶ Split ├──▶ Merge ──▶ Combined Results
├──▶ Task 2 ──┤
└──▶ Task 3 ──┘

Branches without dependencies execute in parallel automatically.

Code:

from utils import helper_function
result = helper_function(data)

Flow-Like:

Board: Utils
└── Event: HelperFunction (data)
Process ──▶ Return Result
Board: Main
└── Event: Process
Call Board: Utils.HelperFunction (data)
Use Result

Boards are your modules. Quick Actions are your exported functions.

Code:

processed = [transform(item) for item in items]

Flow-Like:

Items ──▶ For Each ──▶ Transform ──▶ Collect ──▶ Processed Array

Code:

filtered = [item for item in items if condition(item)]

Flow-Like:

Items ──▶ For Each ──▶ Branch (condition)
True │
Collect ──▶ Filtered Array

Code:

total = sum(item.value for item in items)

Flow-Like:

Variables: running_total = 0
Items ──▶ For Each ──▶ Get Value ──▶ Add to running_total
└──(done)──▶ Get running_total ──▶ Final Total

Code:

response = requests.post(
"https://api.example.com/data",
json={"key": "value"},
headers={"Authorization": "Bearer token"}
)
data = response.json()

Flow-Like:

HTTP Request
├── URL: "https://api.example.com/data"
├── Method: POST
├── Body: {"key": "value"}
└── Headers: {"Authorization": "Bearer token"}
Parse JSON ──▶ data

Code:

with open("file.txt", "r") as f:
content = f.read()
with open("output.txt", "w") as f:
f.write(processed_content)

Flow-Like:

Read to String ("file.txt") ──▶ content
Process Content
Write String ("output.txt", processed_content)

Code:

conn = psycopg2.connect(...)
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE active = true")
users = cursor.fetchall()

Flow-Like:

Register PostgreSQL (connection_string)
SQL Query ("SELECT * FROM users WHERE active = true")
users (array of rows)
ProgrammingFlow-Like
print(variable)Console Log node
BreakpointPause execution (click wire)
Step throughVisual execution trace
Stack traceFollow execution path
Watch variablesInspect any pin value
  1. Run your flow
  2. Click any wire to see its current value
  3. Errors show red highlighting on the failing node
  4. Execution history shows the path taken

Code:

def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0

Flow-Like:

Board: TestAdd
├── Test Case 1:
│ └── Add(2, 3) ──▶ Assert Equals (5)
└── Test Case 2:
└── Add(-1, 1) ──▶ Assert Equals (0)

Run test boards to validate logic.

  • Node execution (Rust runtime)
  • Data passing (zero-copy where possible)
  • Parallel branches (truly concurrent)
  • Native operations (files, HTTP, SQL)
  • Minimize node count in hot paths
  • Use batch operations over loops when available
  • Leverage SQL for data filtering (don’t load all data)
  • Cache expensive computations in variables

When built-in nodes aren’t enough, create custom ones:

#[wasm_bindgen]
pub fn my_custom_function(input: String) -> String {
// Your logic here
format!("Processed: {}", input)
}

This becomes a node you can use in any flow.

Use HTTP Request nodes to call any REST API.

Use the Run Command node to execute shell commands.

Flow-Like flows can be triggered via API endpoints.

Some complex logic may require custom WASM nodes. But most automations work visually.

The runtime is Rust—often faster than Python/JS. The overhead is negligible.

Flow-Like has built-in versioning. Boards also export as JSON for Git.

Yes—share boards, use version history, export/import packages.

Visual diffs show what changed. It’s different but reviewable.

Code executes line-by-line. Flows execute node-by-node following wires.

Nodes take inputs, produce outputs. Side effects are explicit (file writes, HTTP calls).

When you need persistent state, use variables. They’re like class attributes.

Each board is a unit of composition. Like modules or classes.

Nothing runs without an event trigger. They’re your main() functions.

Pain Point in CodeFlow-Like Solution
Dependency managementBundled in nodes
Environment setupJust download and run
Deployment complexityClick to publish
DocumentationVisual is self-documenting
Onboarding teammatesLower barrier
Debugging async flowsVisual trace