Subprocess Workflows
A Subprocess phase runs another published workflow as a nested child. The parent phase waits for the child to complete (or be cancelled), then continues along the outgoing transition that matches the child's exit handler.
Use subprocesses when the same chunk of process appears in multiple parent workflows — background checks, access provisioning, approval chains, domain-specific validation — and you want to maintain it in one place.
When to Use a Subprocess
| Situation | Why subprocess helps |
|---|---|
| Same approval chain in multiple workflows | Edit once, applies everywhere |
| Complex sub-process that clutters the parent canvas | Collapses to a single visible node |
| Process owned by a different team | Team owns and publishes their subprocess; parent workflows compose it |
| Conditional deep flows (e.g. different validation per product line) | Parent picks which subprocess to run; child handles the details |
Rule of thumb: if more than one workflow needs the exact same sequence of phases, it's a candidate.
Making a Workflow Reusable as a Subprocess
A workflow must be marked reusable before other workflows can link to it. Open the workflow's detail page → Interface card → toggle Reusable. Reusable workflows expose three pieces of contract:
isReusable— gate that allows other workflows to link to this oneinputSchema— declared inputs the child expects (name, type, required/optional, description)outputSchema— declared outputs the child guarantees on each END phase (name, type, description)
The schemas are authored in the Interface card alongside the reusability flag. Parents see these schemas in the Subprocess phase editor and the variable-mapping UI uses them to type-check input and output mappings.
Why explicit schemas? Phase 45 introduced typed input/output contracts so parents can map variables with autocomplete + validation, and so the editor can warn when a parent maps a value of the wrong type into a child input. Schemas are stored on the WorkflowVersion, so changing them is part of publishing a new version — never a silent change underneath running parents.
Configuring a Subprocess Phase
Drag Subprocess from the phase palette onto the canvas. In the property panel:
Linked workflow + version
- Linked workflow — any reusable published workflow in your company
- Linked version — pin to a specific version (e.g.
v3) or toLATEST - Switching the linked workflow or version mid-design triggers a cross-version compatibility check: the editor highlights any input/output mappings in your parent that no longer match the new child's
inputSchema/outputSchema, so you can fix them before saving.
Input mapping
The Subprocess editor reads the child's inputSchema and renders a row per declared input. For each child input you map a source from the parent's tier-aware variable references:
phase.*— variables produced earlier in this parent phase or this phase's outputsinstance.*— instance-scoped variables (the parent's running state)system.*— Nembl-reserved system variables (requestId, requesterEmail, etc.)global.*— company-global constants
Required child inputs must have a source; optional inputs can be left blank to use the child's declared default. Type compatibility is checked at editor save time.
Output mapping + handler blocks (per-END outputProjection)
Children can have multiple END phases, each representing a distinct outcome (Approved / Rejected / Failed / Cancelled). On the parent side, the Subprocess phase has one handler block per outgoing transition, and each handler block has its own outputProjection that maps from the child's outputs (as guaranteed by the END the child reached) back to the parent's variables.
Subprocess phase: "Background Check"
├── Handler: Approved
│ outputProjection:
│ instance.bgCheckResult ← child.outcome
│ instance.bgCheckRef ← child.referenceNumber
│ → Transition: "Continue Onboarding"
│
├── Handler: Rejected
│ outputProjection:
│ instance.bgCheckResult ← child.outcome
│ instance.bgCheckReason ← child.failureReason
│ → Transition: "Send Decline Notice"
│
└── Handler: Cancelled (no outputProjection — short-circuit)
→ Transition: "Restart Onboarding"This means different exit handlers can pull different child variables back to the parent, with type-safety guaranteed by the child's outputSchema for that specific END phase.
Runtime Behavior
Launch
When the parent instance reaches the Subprocess phase:
- Nembl resolves which child version to start (pinned or LATEST at activation time)
- Nembl applies the input mapping to build the child's starting variables
- A new
WorkflowInstanceis created for the linked workflow - The child records
parentInstanceIdandparentPhaseIdso it knows where to report back - The parent waits — the subprocess phase stays active while the child is active
Transitions on completion
When the child reaches an END phase, it emits nembl.workflow.subprocess.complete with the END's name. The parent's Subprocess phase:
- Selects the handler block matching the END name (or the default-unlabeled handler if no specific match)
- Runs that handler's
outputProjectionto copy child outputs to parent variables - Fires the handler's outgoing transition
If no handler matches the child's END name and there's no default handler, the parent stalls with an error — the editor catches this at design time.
Parent/child visibility
In the instance viewer:
- The parent shows its current Subprocess phase with a "Running subprocess" indicator and a deep link to the child instance
- The child shows a "Subprocess of parent title" badge and a deep link to the parent
Both parties can be navigated independently.
Cancellation Cascade
When a parent is cancelled:
- If the parent has a Cancel node, the parent routes there; active children are NOT cancelled yet — this allows Resume Workflow to abort the cancellation and pick up where it left off.
- When the parent's cancellation finalizes (all cleanup tasks complete, or no Cancel node exists), all active children are cancelled via cascading
nembl.workflow.cancelevents. - Children that were already completed stay completed — only active children are affected.
When a child is cancelled directly:
- The child finalizes as CANCELLED
- It emits
nembl.workflow.subprocess.completewith nameCancelled - The parent's Subprocess phase runs the
Cancelledhandler (if present) or the default handler
Design tip: always provide a Cancelled handler on any Subprocess phase so the parent can handle child cancellations gracefully.
Variable Tier Namespaces
Variables in subprocess workflows live in tier-aware namespaces. This affects what's writable from inside the child:
| Namespace | Owner | Writable from child? |
|---|---|---|
phase.* | Per-phase scratch | Yes (current phase) |
instance.* | The child's instance | Yes |
system.* | Nembl-reserved | No (read-only) |
global.* | Company-global | No (read-only) |
The parent's variables are never directly writable by the child — only by the parent's outputProjection after the child completes. This isolation prevents children from mutating parent state mid-flight.
Common Patterns
Shared approval chain
Parent workflows like "New Hire Onboarding" and "Contractor Onboarding" both need a manager-approval subprocess. Build one reusable Manager Approval workflow with a single APPROVAL phase plus distinct Approved and Rejected END phases, declare its inputSchema (the candidate, the request type) and outputSchema (the approver, the decision timestamp), then link it from each parent. Change the approver or the SLA once; every parent benefits.
Per-product-line validation
A parent Customer Returns workflow uses a DECISION phase on productLine to route to one of three Subprocess phases, each linked to a product-line-specific validation workflow. The parent stays clean; product teams own their own validation rules + interfaces.
Reusable cleanup
An IT workflow's Cancel node launches a "Cleanup: Release Resources" subprocess instead of listing dozens of cleanup tasks inline. The cleanup workflow declares a minimal inputSchema (the ticket ID) and is maintained by the IT team separately from the customer-facing workflows that invoke it.
Limits
- No recursion detection: a subprocess can link to a workflow that eventually links back to itself. Keep an eye on it, or you'll spawn instances until you hit your instance quota.
- Depth is technically unlimited but keep nesting modest (2–3 levels) for readability and observability.
- All children of a cancelled parent finalize with status CANCELLED — there's no "keep child running after parent cancels" flag.
Troubleshooting
- Parent waits forever — the child is stuck. Check the child's current phase; responsible parties there may have been notified but haven't acted. Resolve at the child level.
- Handler doesn't fire — the child completed with an END name that doesn't match any handler on the Subprocess phase, and there's no default handler. Add the missing handler (check the child's END phase names) or add a default fallback.
- Outputs not visible on parent — verify the handler that fired has the right outputProjection mappings, and that the child's
outputSchemaactually declares those output names. The editor's compatibility check catches this at design time. - Editor warns about input mapping after version switch — the new child version's
inputSchemadiffers from the previous one. Update your mappings before saving. - Cancelled parent but child kept running — this should not happen; it indicates the cancel finalization didn't propagate to the child. Check the Audit Trail for the parent's cancellation events.
Related
- Phases and Transitions — where Subprocess fits in the phase palette
- Workflow Versioning — how the LATEST resolver picks the child version at runtime
- Workflow Execution — parent/child cancellation semantics
- Execution Architecture — the event flow behind subprocess lifecycle (developer reference)