How to Build a Reusable Subworkflow Library

Create reusable workflow components that you can call from any workflow, reducing duplication and simplifying maintenance.

What This Integration Does

Over time, every Spojit account ends up with several workflows that do the same thing: look a customer up by email, validate an address, post a Slack alert in a standard format. Copy-pasting that logic into each new workflow is fast at first, but every time a downstream system changes (a new required field, a different Slack channel, an extra validation rule) you have to track down and patch every copy. Subworkflows let you extract that logic into a single workflow your other workflows call as one step, the same way you'd call a function in code.

Each subworkflow is a normal Spojit workflow with its own Trigger and (optionally) a Response node. The parent workflow drops in a Subworkflow node, picks the target workflow, and maps its inputs. The parent pauses while the child runs through its own trigger and nodes, then the child's final output returns to the parent and the parent continues. Children appear as separate execution-history entries, so failures are visible and debuggable on their own without polluting the parent's logs.

Prerequisites

  • Write access to create and edit workflows in your workspace.
  • At least one piece of logic that's used in two or more existing workflows - the candidate to extract.
  • A naming convention for shared workflows (a Shared: prefix or a dedicated folder works well).

Step 1: Identify the Reusable Logic

Pick a self-contained chunk of work with a clear input and output. Good candidates: customer lookup-or-create, address normalisation, formatting and sending a Slack alert, generating a PDF from a template. Avoid extracting tiny one-step pieces - the overhead of a Subworkflow node isn't worth it. Aim for at least 3 to 4 internal steps.

Step 2: Create the Subworkflow with a Manual Trigger

Create a new workflow named clearly (e.g. Shared: Customer Lookup or Create). Drop a Trigger node and set its type to Manual. A Manual trigger lets the workflow be run from the Run button or invoked as a child, and its output is the request body passed in. When the parent calls this workflow through a Subworkflow node, the data it sends in the node's Input field becomes that body, so decide on the fields you expect (e.g. email and name) and reference them downstream.

Step 3: Build the Internal Logic

Reference the trigger inputs inline with handlebars - for example a Connector node calling the netsuite connector with the list-customers tool, filtered by email = "{{ trigger.email }}". Add a Condition node to branch on whether a customer was found, and a second Connector call to create-customer on the not-found branch. Keep the subworkflow focused - if it starts pulling in unrelated logic, split it into two.

Step 4: Return the Result with a Response Node

End the subworkflow with a Response node that returns a clean, stable payload to the caller. For the customer lookup example:

{
  "customerId": "{{ customer.id }}",
  "isNew": {{ wasCreated }},
  "email": "{{ trigger.email }}"
}

Treat the Response shape as a public contract - other workflows depend on it, so changing field names is a breaking change.

Step 5: Call the Subworkflow from a Parent

In your main workflow, add a Subworkflow node. Pick the shared workflow in the Workflow field, then fill in the Input with the data the child expects, mapping from earlier step output (e.g. email = {{ step1.customer_email }}). The parent pauses until the child returns its final output, and downstream nodes can then reference the result as {{ subworkflow1.customerId }}.

Step 6: Test Both Workflows Independently

Run the subworkflow on its own with the Manual trigger by supplying sample input - this catches contract bugs without dragging a parent through every test. Then run the parent and confirm the mapped variables land in the right place. Once both pass, repeat the extraction for the next candidate: a Send Slack Alert subworkflow, an Address Validation subworkflow, a Generate PDF Report subworkflow, and so on, building up a library.

Tips

  • Use a Shared: prefix or a dedicated folder so library workflows are easy to find amid feature workflows.
  • Keep each subworkflow's Response shape stable: it is the contract the parent maps against, so favour adding fields over renaming them.
  • Subworkflows can call other subworkflows. Nesting is allowed and useful for composition, but avoid deep chains because they get hard to debug.
  • Version-sensitive logic (tax calculations, pricing rules) is the highest-value thing to extract - one fix updates every caller at once.

Common Pitfalls

  • Changing the Response shape - renaming or removing fields silently breaks every parent. Add new fields instead and deprecate old ones gradually.
  • Over-extraction - wrapping a single Connector call in a subworkflow adds overhead without saving meaningful duplication.
  • Hidden side effects - if a subworkflow writes to a database or sends a message, document that on the workflow description so callers don't run it twice expecting it to be safe.
  • Long-running children - because the parent pauses until the child returns, a very slow subworkflow holds the parent open. If the work does not need to block, move it into its own scheduled or webhook-triggered workflow instead of calling it inline.

Testing

Run the subworkflow alone using the Manual trigger with a known-good input, then run it with deliberately bad input to confirm error paths. Once it's stable, call it from a sandbox parent workflow and verify the mapped variables and Response payload look right in the execution log before swapping it into production callers.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.