@servicenow/sdk
Version:
ServiceNow SDK
195 lines (147 loc) • 10.7 kB
Markdown
---
tags: [subflow, flow, automation, reusable, wfa.subflow, assignSubflowOutputs, FlowObject, FlowArray, flowVariables, runAs, runWithRoles]
---
# Subflow
API reference for the `Subflow()` constructor, the `wfa.subflow()` invocation helper, and the `wfa.flowLogic.assignSubflowOutputs()` output helper.
Subflows are reusable units of automation with typed inputs and outputs. They are invoked from inside a Flow or another Subflow via `wfa.subflow()` -- they have no trigger of their own.
---
## Subflow()
Defines a reusable callable subflow with typed inputs, typed outputs, and an optional body.
### Signature
```typescript fluent
Subflow<TInputs, TOutputs, TFlowVariables, TStages>(
config: SubflowConfig<TInputs, TOutputs, TFlowVariables, TStages>,
body?: (params: {
inputs: TInputs,
outputs: TOutputs,
flowVariables: TFlowVariables,
stages: TStages
}) => void
): Subflow<TInputs, TOutputs>
```
### Config Parameters
| Parameter | Type | Default | Required | Description |
| ------------------ | ----------------------------------- | ---------- | -------- | -------------------------------------------------------------------------- |
| `$id` | `string` / `Now.ID[...]` | - | Yes | Unique identifier |
| `name` | `string` | - | Yes | Display name shown in Flow Designer |
| `description` | `string` | - | No | What the subflow does |
| `annotation` | `string` | - | No | Annotation text visible on the designer canvas |
| `runAs` | `'system'` \| `'user'` | - | No | Execution context. `'system'` bypasses ACLs |
| `runWithRoles` | `(string \| Role)[]` | `[]` | No | Role sys_ids **or** `Role` objects granting temporary elevated permissions |
| `flowPriority` | `'LOW'` \| `'MEDIUM'` \| `'HIGH'` | - | No | Execution queue priority |
| `protectionPolicy` | `'read'` \| `''` | `''` | No | If `'read'`, subflow body is read-protected in the runtime |
| `access` | `'public'` \| `'package_private'` | `'public'` | No | Visibility scope |
| `category` | `string` | - | No | Grouping category in Flow Designer |
| `inputs` | `Record<string, Column>` | `{}` | No | Input schema; passed by the caller via `wfa.subflow()` |
| `outputs` | `Record<string, Column>` | `{}` | No | Output schema; set inside body via `assignSubflowOutputs` |
| `flowVariables` | `Record<string, Column>` | `{}` | No | Internal variables scoped to this subflow execution |
| `stages` | `Record<string, FlowStageConfig>` | `{}` | No | Named stage declarations for tracking subflow execution progress. Each key must match the `value` field inside the corresponding `FlowStage()` call |
### Body Function
The body is **optional**. When supplied, it receives a `params` object exposing the typed schemas:
| `params` key | Type | Description |
| --------------- | ---------------- | ------------------------------------------------------------------------ |
| `inputs` | `TInputs` | Typed input pills (use `wfa.dataPill(params.inputs.field, 'type')`) |
| `outputs` | `TOutputs` | Output schema reference. **Pass this to `assignSubflowOutputs`** |
| `flowVariables` | `TFlowVariables` | Internal mutable variables (read via data pill, write via `setFlowVariables`) |
| `stages` | `TStages` | Named stages declared in the config. Activate via `wfa.stage(params.stages.x)` |
The body may contain `wfa.action()`, `wfa.flowLogic.*`, and nested `wfa.subflow()` calls.
`Subflow(config)` with no body is valid -- useful for stub definitions or cross-file references.
---
## wfa.subflow()
Invokes a subflow from inside a Flow body or another Subflow body.
### Signature (typed)
```typescript fluent
wfa.subflow<TInputs, TOutputs>(
subflow: Subflow<TInputs, TOutputs>,
instanceConfig: {
$id: string,
annotation?: string,
uuid?: string,
showSubflowStage?: boolean
},
inputs: TInputs & { waitForCompletion?: boolean }
): TOutputs & { type: 'subflow' }
```
### Signature (sys_id fallback)
When the subflow's typed definition cannot be imported (cross-application or unresolvable), pass the subflow's sys_id string directly. The return type allows arbitrary property access for downstream data pill references.
```typescript fluent
wfa.subflow(
subflowSysId: string,
instanceConfig: { $id: string, annotation?: string, ... },
inputs: Record<string, any> & { waitForCompletion?: boolean }
)
```
### Parameters
| Parameter | Type | Default | Required | Description |
| --------------------- | ----------------------------- | ------- | -------- | ---------------------------------------------------------------------------------------------- |
| `subflow` | `Subflow` \| `string` (sys_id) | - | Yes | Exported subflow constant **or** a string sys_id when the definition is not importable |
| `instanceConfig.$id` | `string` | - | Yes | Unique identifier for this invocation instance |
| `annotation` | `string` | - | No | Description of this specific invocation |
| `uuid` | `string` | - | No | Stable UUID for this instance (rarely set by hand; usually generated) |
| `showSubflowStage` | `boolean` | - | No | If `true`, a dedicated `sys_hub_flow_stage` of `type: 'subflow'` is created for this instance |
| `inputs` | `TInputs` | - | Yes | Input values matching the subflow's input schema |
| `waitForCompletion` | `boolean` | `false` | No | If `true`, the caller waits for the subflow to complete before continuing. **Belongs inside the `inputs` object, not `instanceConfig`** |
### Return Value
Returns a typed output object. Access output fields as data pills:
```typescript fluent
const result = wfa.subflow(mySubflow, { $id: Now.ID["instance"] }, { ... });
wfa.dataPill(result.outputField, "string"); // use output in downstream actions
wfa.dataPill(result.recordOutput, "reference");
```
---
## wfa.flowLogic.assignSubflowOutputs()
Sets the subflow's output values. Must be called inside the subflow body for outputs to be visible to the caller.
### Signature
```typescript fluent
wfa.flowLogic.assignSubflowOutputs(
definition: { $id: string, annotation?: string },
outputSchema: TOutputs, // always pass params.outputs
values: Partial<TOutputs> // fields to assign; omitted fields are undefined
)
```
### Parameters
| Parameter | Type | Required | Description |
| -------------- | ------------------- | -------- | ------------------------------------------------------------------------ |
| `$id` | `string` | Yes | Unique identifier for this assignment node |
| `annotation` | `string` | No | Description/comment |
| `outputSchema` | `TOutputs` | Yes | **Always pass `params.outputs`** -- do not construct a custom object |
| `values` | `Partial<TOutputs>` | Yes | Key/value pairs to assign. Values may be literals or data pills |
**⚠️ Type-only helper.** This call is erased at runtime; it exists for compile-time type safety. The actual runtime assignment happens in the underlying flow stage.
---
## Column Types
Import from `@servicenow/sdk/core` for `inputs`, `outputs`, and `flowVariables` schemas:
| Type | Description |
| ----------------- | ---------------------------------------- |
| `StringColumn` | Text values |
| `IntegerColumn` | Whole numbers |
| `BooleanColumn` | True/false values |
| `DecimalColumn` | Decimal numbers (fixed precision) |
| `FloatColumn` | Floating-point numbers |
| `DateTimeColumn` | Date and time values |
| `ReferenceColumn` | Reference to a ServiceNow table record |
| `GenericColumn` | Flexible type via `columnType` property |
| `JsonColumn` | JSON string values |
Import from `@servicenow/sdk/automation` for complex types:
| Type | Description |
| ------------ | -------------------------------------------------------- |
| `FlowObject` | Nested object with typed `fields` |
| `FlowArray` | Array of typed elements (use with `elementType`) |
### FlowObject example
```typescript fluent
import { FlowObject } from "@servicenow/sdk/automation";
import { StringColumn, IntegerColumn } from "@servicenow/sdk/core";
inputs: {
requestData: FlowObject({
label: "Request Data",
mandatory: false,
fields: {
title: StringColumn({ label: "Title" }),
priority: IntegerColumn({ label: "Priority" })
}
})
}
// Access a nested field inside the body:
// wfa.dataPill(params.inputs.requestData.title, "string")
```
---
For complete examples, usage patterns, best practices, and anti-patterns, see the [Subflow Guide](../../guides/wfa-subflow-guide.md).