Workflow names: Use descriptive names that state what the workflow does: "Auto-assign P0 tickets to on-call", not "Workflow 1".
Step names: Rename steps to describe their purpose. "Check if P0" is clearer than "If Else 1" when debugging.
Router route names: Use descriptive names that become output port identifiers: "urgent", "billing", "escalate" - not "Route 1", "Route 2".
If/Else: Best for binary decisions (true/false, yes/no). Use when there are exactly two paths.
Router: Best for multi-way branching (3+ paths) where each path completes its own work and ends. Keeps the canvas flat and readable versus deeply nested If/Else blocks.
Route & Merge: Use when the branches need to converge - the work after the branch is shared, several branches must finish before continuing, or you want to proceed with whichever branch finishes first. Also the right choice when a step after the branch would otherwise have to be duplicated on every path.
Router with "First Match Only": Use when routes are mutually exclusive (e.g., priority-based routing where a ticket is exactly one priority level).
Router without "First Match Only" (default): Use when multiple routes can apply simultaneously (e.g., a ticket can be both "urgent" AND "billing-related").
Router and Route & Merge are the same node in two modes, so this is not a decision you are locked into. Transform between them from the node's ellipsis menu while the workflow is in draft, and the branch conditions carry over.
Use native nodes for deterministic operations: updating fields, checking enum values, simple comparisons, timestamp math. Native nodes are faster, cheaper, and predictable.
Use Ask AI for tasks requiring judgment: classifying free-text content, summarizing conversations, generating draft replies, routing based on intent rather than keywords.
Do not use Ask AI for: timestamp conversions, extracting field values, simple if/else conditions, or anything with a deterministic answer.
Scope triggers as tightly as possible. A trigger on "Ticket Created" with no filters fires on every single ticket. A trigger filtered to priority = P0 AND applies_to_part = Payments fires only for the tickets that need this workflow.
Benefits:
Fewer unnecessary workflow runs.
Less noise in the Runs tab.
Reduced chance of the workflow acting on objects it should not touch.
Build and validate the workflow in Draft mode.
Publish and test with a sample event (for example, create a test ticket that matches the trigger filters).
Open the Runs tab and inspect the run. Verify each step's input/output values.
Check that the expected changes were made to the target object.
If something is wrong, pause, edit, and republish.
Add error paths to any step that:
Calls an external API (HTTP node): the external service may be down or return unexpected responses.
Runs custom code (Code node): code may throw exceptions.
Operates on variable data that could be null or malformed.
A workflow with error paths is resilient. A workflow without them stops at the first failure.
Built-in retry policy: For 429 (Too Many Requests) errors, the workflow engine retries automatically if the operation properly propagates the error. Default retry policy: 3 total attempts - initial attempt, first retry after 30 seconds, second retry after 1 minute. Not all operations support this - check the run inspector to verify if retries occurred.
Plan your data flow before building. Identify which data each step needs and verify it is available from an upstream step.
If a step needs data that is not in the trigger output, add a Get operation (for example, Get Account, Get Issue) to fetch the full object, then reference its output.
Use the Code node to reshape data when the native output format does not match the input format of a downstream step.
Use scope variables (init_variable / set_variable) when you need to aggregate or modify a value across loop iterations or branches.