Skip to main content
Version: Latest (4.6.0)

Subflow

Subflow(config, body)

Creates a reusable Subflow with typed inputs, outputs, and an optional body. Subflows are invoked from inside a Flow or another Subflow via wfa.subflow().

Parameters

config

SubflowDefinition<TInputs, TOutputs, TFlowVariables>

Subflow configuration — name, inputs, outputs, variables, and execution settings.

Properties:

  • $id (required): string | number | ExplicitKey<string>

  • name (required): string

  • description (optional): string

  • runAs (optional): 'user' | 'system'

  • runWithRoles (optional): string[]

  • flowPriority (optional): 'LOW' | 'MEDIUM' | 'HIGH'

  • access (optional): 'public' | 'package_private'

  • category (optional): string

  • inputs (optional): Record<string, Column> — Input schema; passed by the caller via wfa.subflow().

  • outputs (optional): Record<string, Column> — Output schema; set inside body via assignSubflowOutputs.

  • flowVariables (optional): Record<string, Column> — Internal variables scoped to this subflow execution.

body (optional)

(params: { inputs: TInputs, outputs: TOutputs, flowVariables: TFlowVariables }) => void

The subflow body function. May contain wfa.action(), wfa.flowLogic.*, and nested wfa.subflow() calls. Body is optional — Subflow(config) with no body is valid for stub definitions.

Column Types

Import from @servicenow/sdk/core for inputs, outputs, and flowVariables.

TypeDescription
StringColumnText values
IntegerColumnWhole numbers
BooleanColumnTrue/false values
ReferenceColumnReference to a ServiceNow table record
DecimalColumnDecimal numbers (fixed precision)
FloatColumnFloating-point numbers
DateTimeColumnDate and time values

Import from @servicenow/sdk/automation for complex types:

TypeDescription
FlowObjectNested object with typed fields
FlowArrayArray of typed elements

Invoking a Subflow

Use wfa.subflow() inside a Flow or another Subflow to invoke a defined subflow.

const result = wfa.subflow(
mySubflow,
{ $id: Now.ID['instance_id'], annotation: 'optional description' },
{ inputField: wfa.dataPill(someValue, 'string'), waitForCompletion: true }
)
ParameterDescription
subflowThe exported subflow constant to invoke.
$idUnique identifier for this invocation instance.
annotationOptional description for this invocation instance.
inputsInput values matching the subflow's input schema.
waitForCompletionIf true, the calling flow waits for the subflow to complete before continuing.

Access outputs via data pills: wfa.dataPill(result.outputField, 'string').

Setting Outputs

Use wfa.flowLogic.assignSubflowOutputs() inside the subflow body to return data to the caller.

wfa.flowLogic.assignSubflowOutputs(
{ $id: Now.ID['assign_outputs'] },
params.outputs,
{ success: true, record: wfa.dataPill(lookup.Record, 'reference') }
)

Examples

Subflow Definition

import { Subflow, wfa, action } from '@servicenow/sdk/automation'
import { StringColumn, BooleanColumn, ReferenceColumn } from '@servicenow/sdk/core'

export const validateUserSubflow = Subflow(
{
$id: Now.ID['validate_user_subflow'],
name: 'Validate User Subflow',
runAs: 'system',
inputs: {
userId: StringColumn({ label: 'User Sys ID', mandatory: true }),
},
outputs: {
isValid: BooleanColumn({ label: 'Is Valid', mandatory: true }),
userRecord: ReferenceColumn({ label: 'User Record', referenceTable: 'sys_user' }),
},
},
(params) => {
const lookup = wfa.action(
action.core.lookUpRecord,
{ $id: Now.ID['lookup_user'] },
{
table: 'sys_user',
conditions: `sys_id=${wfa.dataPill(params.inputs.userId, 'string')}`,
}
)

wfa.flowLogic.if(
{
$id: Now.ID['check_user_found'],
condition: `${wfa.dataPill(lookup.Record.sys_id, 'string')}ISNOTEMPTY`,
},
() => {
wfa.flowLogic.assignSubflowOutputs(
{ $id: Now.ID['assign_valid'] },
params.outputs,
{ isValid: true, userRecord: wfa.dataPill(lookup.Record, 'reference') }
)
}
)

wfa.flowLogic.else({ $id: Now.ID['user_not_found'] }, () => {
wfa.flowLogic.assignSubflowOutputs(
{ $id: Now.ID['assign_invalid'] },
params.outputs,
{ isValid: false }
)
})
}
)

Invoking from a Flow

import { Flow, wfa, trigger, action } from '@servicenow/sdk/automation'
import { validateUserSubflow } from './validate-user-subflow.now'

export const onboardUserFlow = Flow(
{
$id: Now.ID['onboard_user_flow'],
name: 'Onboard User Flow',
runAs: 'system',
},
wfa.trigger(
trigger.record.created,
{ $id: Now.ID['trg_onboard'] },
{ table: 'sys_user', condition: 'active=true', run_flow_in: 'background' }
),
(params) => {
const validation = wfa.subflow(
validateUserSubflow,
{ $id: Now.ID['validate_user_instance'] },
{
userId: wfa.dataPill(params.trigger.current.sys_id, 'string'),
waitForCompletion: true,
}
)

wfa.flowLogic.if(
{
$id: Now.ID['check_valid'],
condition: `${wfa.dataPill(validation.isValid, 'boolean')}=true`,
},
() => {
wfa.action(
action.core.log,
{ $id: Now.ID['log_success'] },
{ log_level: 'info', log_message: 'User validated — proceeding with onboarding' }
)
}
)
}
)

For guidance on creating and invoking reusable subflows, see the wfa-subflow-guide topic.