What is a subflow?
A subflow is a reusable Flow Designer automation that is called explicitly from a parent flow or another subflow rather than firing on its own trigger. You define input variables (what it needs) and output variables (what it returns), and the calling flow maps data pills to those inputs and reads the outputs after the subflow completes.
The analogy to scripting is direct: a subflow is to a flow what a Script Include is to a Business Rule — a named, testable, reusable unit of logic that multiple callers can use.
When to create a subflow
Create a subflow when:
- The same sequence of steps appears in more than one flow — if you find yourself building the same notification logic in three different flows, it is time for a "Send Escalation Notification" subflow
- A sequence is logically self-contained — "Create Approval Task" has a clear start, defined inputs, and a defined output. It makes sense as a subflow even if only one flow calls it initially
- A sequence is complex enough to test independently — subflows can be tested in isolation with the Test button, which is far easier than triggering the full parent flow
- You want to hide implementation details — a flow that calls "Provision User in Active Directory" is readable even to a business analyst; the 15 steps inside that subflow do not need to be visible at the parent flow level
- You are using retry logic — the operation being retried must be in a subflow so it can be called repeatedly from the Catch block
Creating a subflow
In Flow Designer: New → Subflow. Give it a clear, verb-noun name that describes what it does:
- Send Manager Escalation Notification
- Create Approval Task
- Get User Manager Chain
- Validate and Format Phone Number
- Create Jira Issue from Incident
Naming conventions matter because subflows appear in a shared list that grows over time. A clear name tells any developer what the subflow does without opening it.
Defining inputs and outputs
Inputs and outputs are defined in the subflow's Inputs/Outputs section (top of the subflow editor). Every input and output has a name, a type, and optionally a description.
Input variable types
- String — text values, sys_ids, field values
- Integer — numeric values, counts, durations
- Boolean — true/false flags
- Reference — a reference to a specific table record (e.g., Reference: Incident)
- Date/Time — GlideDateTime values
- Array — lists of values
Example: Send Manager Escalation Notification subflow
Subflow Name: Send Manager Escalation Notification
Inputs:
- incident_record (Reference: Incident) — required
Description: The incident to escalate
- escalation_reason (String) — required
Description: Why this is being escalated
- escalation_level (Integer) — optional, default: 1
Description: 1=first escalation, 2=executive escalation
Outputs:
- notification_sent (Boolean)
Description: True if notification was sent successfully
- notification_sys_id (String)
Description: Sys_id of the notification record created
Example: Create Jira Issue subflow
Subflow Name: Create Jira Issue from Incident
Inputs:
- incident_record (Reference: Incident) — required
- jira_project_key (String) — required, e.g. "OPS"
- issue_type (String) — optional, default: "Bug"
Outputs:
- jira_issue_key (String) — e.g. "OPS-1234", empty if failed
- jira_issue_url (String) — full URL to the Jira issue
- creation_success (Boolean)
Building the subflow steps
Inside the subflow, input variables are available as data pills from the Subflow Inputs section. Build steps using those pills exactly as you would in a regular flow.
Setting output values: use the Set Flow Variable step (or directly set the output variable in a Script step) to assign values to output variables before the subflow ends:
// In a Script step inside the subflow:
// Set output variables that the calling flow will read
outputs.jira_issue_key = parsedResponse.key;
outputs.jira_issue_url = 'https://company.atlassian.net/browse/' + parsedResponse.key;
outputs.creation_success = true;
Calling a subflow from a parent flow
In the parent flow, add an Action step → Flow Logic → Run Subflow. Select your subflow from the list. The UI will show all defined inputs — map each one using data pills from the parent flow context.
Parent flow step: Run Subflow
Subflow: Create Jira Issue from Incident
Inputs:
incident_record → Trigger > Incident Record (data pill)
jira_project_key → "OPS" (hardcoded string)
issue_type → Script output > issue_type_calculated (data pill)
After the subflow step, output variables from the subflow appear as data pills in the parent flow under the subflow step's context:
→ Run Subflow — Create Jira Issue > Jira Issue Key
→ Run Subflow — Create Jira Issue > Creation Success
→ Run Subflow — Create Jira Issue > Jira Issue URL
Error handling in and around subflows
Errors inside the subflow
Subflows should handle their own errors where possible. Wrap risky operations (REST calls, lookups) in Try/Catch blocks inside the subflow. If the error is recoverable at the subflow level, handle it internally and set an output variable to indicate success or failure:
// Inside subflow — Catch block sets failure output
Catch (Error)
├── Step: Log error with incident context
├── Step: Set Output Variable — creation_success = false
└── Step: Set Output Variable — jira_issue_key = ""
// Flow continues — error is handled
Errors that escape the subflow
If an error is not caught inside the subflow, it propagates to the calling flow. This means the parent flow's Catch block (if any) will intercept it. Design this intentionally — some errors should be handled by the subflow, others should surface to the parent flow for broader error handling.
// In parent flow — wrapping subflow call in Try/Catch
Try
└── Run Subflow — Create Jira Issue from Incident
Catch
└── Handle "subflow failed" case — notify, log, create incident
For the complete error handling patterns, see Flow Designer error handling.
Subflow versioning
Subflows support versioning. When you publish a new version of a subflow, existing flows that call the old version continue to use it — they do not automatically upgrade to the new version. This prevents breaking changes from propagating unexpectedly.
To update a calling flow to use the new subflow version:
- Open the calling flow
- Click on the Run Subflow step
- Change the version selector to the new version
- Remap any inputs/outputs that changed
- Publish the updated calling flow
This versioning model means you can safely make breaking changes to a subflow without disrupting all existing callers at once — you control when each caller upgrades.
Testing subflows independently
One of the biggest advantages of subflows is independent testability. Click the Test button in the subflow editor to run the subflow with manually specified input values — without triggering the parent flow or waiting for a specific record change.
Testing: Send Manager Escalation Notification
Inputs for test:
incident_record: sys_id of a test incident
escalation_reason: "Test escalation — please ignore"
escalation_level: 1
Expected outputs after test:
notification_sent: true
notification_sys_id: [a valid sys_id]
Test all paths — not just the happy path. Test with a missing optional input (verify the default value works), test with an invalid incident sys_id (verify the error handling works), test with each escalation level.
Production subflow patterns
Pattern 1 — Notification subflow
Used by multiple flows that all need to notify a user and their manager in a consistent format:
Subflow: Send Incident Escalation Notification
Inputs: incident_record (Reference: Incident), recipients (String — comma-separated emails), urgency (Integer)
Steps:
1. Look Up Manager from assigned_to user
2. Build notification body (Script step)
3. Send Email action with dynamic recipients
4. Create Notification History record
Outputs: emails_sent (Integer), success (Boolean)
Pattern 2 — Data enrichment subflow
Fetches related data and returns it as structured output for the calling flow:
Subflow: Get Incident Context
Inputs: incident_record (Reference: Incident)
Steps:
1. Look Up caller details (user record)
2. Look Up assignment group manager
3. Look Up related CMDB CI
4. Script step — build context object
Outputs: caller_email (String), group_manager_email (String), ci_name (String), ci_environment (String)
Pattern 3 — Retry-compatible operation subflow
Any operation that needs retry logic must be in a subflow so the Catch block in the parent flow can call it again:
Subflow: Call External Provisioning API
Inputs: user_sys_id (String), system_name (String), access_level (String)
Steps:
1. Try: REST Action — POST to provisioning API
2. Catch: Set output success = false, log error
3. Set output: success = true, user_id = response.userId
Outputs: success (Boolean), external_user_id (String), error_message (String)
// Parent flow retry logic:
Try: Run Subflow — Call External Provisioning API
Catch:
If retry_count < 3:
Wait 30 seconds
Increment retry_count
Run Subflow again
Else:
Create incident for manual handling
What not to put in a subflow
Subflows are powerful but not appropriate for everything:
- Single steps — a subflow that contains only one step adds navigation overhead without reuse benefit. If the logic is one REST call, keep it inline unless multiple flows use it
- Flow-specific steps — steps that reference the parent flow's specific trigger record and would need different logic for every caller are not good subflow candidates
- Very high-frequency operations — subflow calls have slightly more overhead than inline steps. For flows that fire thousands of times per hour, keep frequently-executed steps inline where possible
Related Flow Designer guides:
- Flow Designer triggers — understanding what starts a flow
- Error handling — building Try/Catch around subflow calls
- Data pills and variables — working with subflow inputs and outputs
- Best practices — subflows as part of overall flow quality
- Flow Designer vs Business Rules — when to use flows at all