Subflows in ServiceNow Flow Designer: The Complete Guide

Subflows are the Flow Designer equivalent of a function — reusable automation blocks that accept inputs, execute a sequence of steps, and return outputs. They are how you avoid duplicating logic across multiple flows and how you build automation at scale. A well-designed library of subflows makes building new flows faster, makes existing flows easier to read, and gives you a single place to fix bugs when the underlying logic needs to change. This guide covers everything: when to create subflows, defining inputs and outputs, calling from parent flows, error handling in subflows, versioning, testing, and real production patterns.

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:

  1. Open the calling flow
  2. Click on the Run Subflow step
  3. Change the version selector to the new version
  4. Remap any inputs/outputs that changed
  5. 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:

The complete Flow Designer reference

The NowSpectrum Flow Designer Playbook covers triggers, actions, subflows, error handling, and 10 production-ready flow examples — 29 pages of practical reference.

Get the Flow Designer Playbook →
← Back to all posts