When a workflow exceeds approximately 20 nodes, it becomes difficult to read, debug, and modify safely.
When a workflow exceeds approximately 20 nodes, it becomes difficult to read, debug, and modify safely. Split it into smaller sub-workflows, each handling a single responsibility. The parent workflow orchestrates the sub-workflows using the Execute Sub-Workflow node, passing data in and receiving results back. This mirrors the function decomposition principle from software engineering.
Real-world example: A monolithic "Order Processing" workflow with 45 nodes handles: order validation, inventory check, payment processing, shipping label generation, and customer notification. Refactored into sub-workflows:
Parent workflow: "Orders - Process New Order"
[Webhook: New Order]
→ [Execute Sub-Workflow: "Orders - Validate"]
→ [IF: valid]
→ [Execute Sub-Workflow: "Inventory - Reserve Stock"]
→ [Execute Sub-Workflow: "Payments - Charge Customer"]
→ [Execute Sub-Workflow: "Shipping - Generate Label"]
→ [Execute Sub-Workflow: "Notifications - Order Confirmation"]
```text
Each sub-workflow definition:
```text
"Orders - Validate" (6 nodes)
Input: order object
Output: { valid: boolean, errors: string[] }
"Inventory - Reserve Stock" (8 nodes)
Input: line_items array
Output: { reserved: boolean, warehouse_id: string }
"Payments - Charge Customer" (5 nodes)
Input: { customer_id, amount, currency }
Output: { charge_id, status }
"Shipping - Generate Label" (7 nodes)
Input: { address, items, warehouse_id }
Output: { tracking_number, label_url }
"Notifications - Order Confirmation" (4 nodes)
Input: { customer_email, order_summary, tracking_number }
Output: { sent: boolean }
```text
> **Note: Data Passing**
>
> Sub-workflows receive the output of the node connected to the Execute Sub-Workflow trigger. Return data from the sub-workflow using the last node's output. Keep interfaces (inputs/outputs) small and well-defined -- pass only the data each sub-workflow needs.
The refactored system is easier to test (run each sub-workflow independently), debug (failures point to a specific sub-workflow), and modify (change shipping logic without touching payment code).
**Related:** [Always Set an Error Workflow on Every Production Workflow](../error-handling-and-reliability/01-always-set-an-error-workflow-on-every-production-workflow.md) | [Use "Pin Data" to Freeze Node Output](../testing-and-debugging/01-use-pin-data-to-freeze-node-output.md)
I build production n8n and Cloudflare automation for teams — the same engineering behind HarperFlow. Fixed-price, escrow-protected, US-based.