SDK 4.3.0
@servicenow/sdk — Release Notes
Version: 4.3.0
Availability: npm — https://www.npmjs.com/package/@servicenow/sdk
🚀 Overview
Version 4.3.0 introduces the highly anticipated Flow API, significant build and transform performance improvements, expanded Service Catalog support, and several new platform capabilities.
This release focuses on enabling workflow-as-code, improving developer productivity, and strengthening type safety across UI and automation development.
🎊 New Fluent APIs
Flow API (MVP)
The Flow API enables building ServiceNow workflows entirely in code using Fluent. Please try this out if you are a Flow user, and give us feedback in the discussions area, we plan to keep enhancing Flows in the next few releases!
Benefits include:
- Workflow-as-code
- AI-assisted development
- Pull request reviews
- Standardized development workflows
Supported Capabilities
Flow Definition
- Name, description, runAs
- Flow priority and protection
- Typed flow variables
Triggers
- Record:
created,updated,createdOrUpdated - Scheduled:
daily,weekly,monthly,repeat,runOnce - Application:
inboundEmail,remoteTableQuery,knowledgeManagement,slaTask
Actions
- Record CRUD operations
- Communication (email, SMS, notifications, approvals)
- Attachment management
- Email utilities
- Core utilities and task automation
Flow Logic
- Conditional branching (
if,elseIf,else) - Loops (
forEach,exitLoop,skipIteration) - Variable management
- Flow control and delays
Data & Types
wfa.dataPill()data referencing- Full TypeScript type safety
- Reference dot-walking support
MVP Limitations
The following capabilities are planned for future releases:
- ❌ Subflow invocation
- ❌ Try/Catch error handling
- ❌ Step rewind (Go-Back-To)
- ❌ Service Catalog trigger
- ❌ Catalog actions
- ❌ DateTime flow variables (use
StringColumnworkaround)
Example
An incident severity alert flow — triggers on incident creation, branches by severity, notifies stakeholders, and sets state to In Progress.
import { action, Flow, wfa, trigger } from '@servicenow/sdk/automation'
export const incidentSeverityAlertFlow = Flow(
{
$id: Now.ID['incident_severity_alert_flow'],
name: 'Incident Severity Alert Flow',
description: 'Notifies team based on incident severity and sets state to In Progress',
},
wfa.trigger(
trigger.record.created,
{ $id: Now.ID['incident_created_trigger'] },
{ table: 'incident', condition: 'origin=NULL', run_flow_in: 'background' }
),
(params) => {
// Log the new incident
wfa.action(
action.core.log,
{ $id: Now.ID['log_incident'] },
{
log_level: 'info',
log_message: `New incident: ${wfa.dataPill(params.trigger.current.short_description, 'string')}`,
}
)
// High severity — notify manager + SMS all assignees
wfa.flowLogic.if(
{
$id: Now.ID['check_high'],
condition: `${wfa.dataPill(params.trigger.current.severity, 'string')}=1`,
},
() => {
wfa.action(
action.core.sendNotification,
{ $id: Now.ID['notify_manager'] },
{
table_name: 'incident',
record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
notification: 'high_severity_manager_notification',
}
)
wfa.flowLogic.forEach(
wfa.dataPill(params.trigger.current.additional_assignee_list, 'array.string'),
{ $id: Now.ID['foreach_assignees'] },
() => {
wfa.action(
action.core.sendSms,
{ $id: Now.ID['sms_assignee'] },
{
recipients: wfa.dataPill(params.trigger.current.additional_assignee_list, 'array.string'),
message: `High severity: ${wfa.dataPill(params.trigger.current.short_description, 'string')}`,
}
)
}
)
}
)
// Medium severity — SMS assignees only
wfa.flowLogic.elseIf(
{
$id: Now.ID['check_medium'],
condition: `${wfa.dataPill(params.trigger.current.severity, 'string')}=2`,
},
() => {
wfa.flowLogic.forEach(
wfa.dataPill(params.trigger.current.additional_assignee_list, 'array.string'),
{ $id: Now.ID['foreach_assignees_medium'] },
() => {
wfa.action(
action.core.sendSms,
{ $id: Now.ID['sms_assignee_medium'] },
{
recipients: wfa.dataPill(params.trigger.current.additional_assignee_list, 'array.string'),
message: `Medium severity: ${wfa.dataPill(params.trigger.current.short_description, 'string')}`,
}
)
}
)
}
)
// Always set state to In Progress
wfa.action(
action.core.updateRecord,
{ $id: Now.ID['update_state'] },
{
table_name: 'incident',
record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
values: TemplateValue({ state: '2' }),
}
)
}
)🧾 Service Catalog Enhancements
Added support for Service Catalog and supporting entities:
- Catalog Client Scripts (
catalog_script_client) - Catalog Items (
sc_cat_item) - Catalog UI Policies (
catalog_ui_policy) - Catalog Variables (
item_option_new) - Variable Sets (
item_option_new_set) - Record Producers (
sc_cat_item_producer)
Catalog Variables
Fluent provides 31 different types of catalog variables to support a wide range of form input needs. Each variable type has a specific function that creates a properly configured variable object.
Example
CatalogItem({
$id: Now.ID['basic_catalog_item'],
name: 'Basic Laptop Request',
shortDescription: 'Request a standard laptop for business use',
description: 'Use this form to request a standard laptop for business use. Approval from your manager is required.',
catalogs: [catalogServiceCatalog],
categories: [categoryHardware],
variableSets: [{ variableSet: userInfoVarSet, order: 100 }],
executionPlan: '523da512c611228900811a37c97c2014',
})
CatalogClientScript({
$id: Now.ID['new-laptop-client-script'],
name: 'Required By Date Validation',
script: `function onSubmit() {
var reqDate = g_form.getValue('required_by_date');
var today = new Date();
var selectedDate = new Date(reqDate);
var diffDays = (selectedDate - today) / (1000 * 60 * 60 * 24);
if (diffDays < 7) {
alert('Required By date must be at least 7 days from today.');
return false;
}
return true;
}
`,
type: 'onSubmit',
catalogItem: requestNewLaptop,
appliesOnRequestedItems: true,
appliesOnCatalogTasks: true,
appliesOnTargetRecord: true,
vaSupported: true,
})
VariableSet({
$id: 'contact_info_set',
title: 'Contact Information',
internalName: 'contact_information',
description: 'Standard contact information fields including phone, email, and address',
type: 'singleRow',
order: 100,
})
CatalogUIPolicy({
$id: Now.ID['employee_request_ui_policy_external_1'],
shortDescription: 'If urgent is true, require manager approval and show department',
catalogCondition: `${departmentVariableSet.variables.urgent} === true`,
variableSet: departmentVariableSet,
appliesTo: 'set',
actions: [
{
variableName: departmentVariableSet.variables.department,
order: 100,
mandatory: true,
visible: true,
}
],
});
CatalogItemRecordProducer({
$id: Now.ID['basic_incident_producer'],
name: 'Report an Incident',
shortDescription: 'Create a new incident ticket',
description: '<p>Use this form to report IT issues and incidents.</p>',
table: 'incident',
catalogs: [catalogServiceCatalog],
categories: [categoryIncidents],
variableSets: [
{ variableSet: incidentDetailsVarSet, order: 100 },
],
hideSaveAsDraft: false,
mandatoryAttachment: false,
hideAttachment: true,
availableFor: [userCriteriaITStaff],
})Email Notification
Creates an Email Notification (sysevent_email_action) in ServiceNow.
import { EmailNotification } from '@servicenow/sdk/core'
EmailNotification({
table: 'incident',
name: 'Incident Assigned Notification',
description: 'Notification sent when an incident is assigned',
triggerConditions: {
generationType: 'engine',
onRecordInsert: true,
onRecordUpdate: true,
condition: 'assigned_toISNOTEMPTY'
},
recipientDetails: {
recipientFields: ['assigned_to'],
sendToCreator: false
},
emailContent: {
contentType: 'text/html',
subject: 'Incident ${number} assigned to you',
messageHtml: '<p>You have been assigned incident ${number}.</p>',
importance: 'high'
}
})Workspace
Configure a Workspace record (ux_workspace) for managing business entities in ServiceNow. A Workspace provides automatic page generation, standardized navigation, and table integration with landing, list, and detail pages.
import { Workspace, UxListMenuConfig, Applicability, Role, Dashboard } from '@servicenow/sdk/core';
// 1. Define roles and applicability
const userRole = Role({
$id: Now.ID['incident_user_role'],
name: 'x_myapp_incident.user',
containsRoles: ['canvas_user']
});
const applicability = Applicability({
$id: Now.ID['incident_applicability'],
name: 'Incident Users',
roles: [userRole]
});
// 2. Create list configuration
const incidentListConfig = UxListMenuConfig({
$id: Now.ID['incident_list_config'],
name: 'Incident List Configuration',
description: 'Navigation for Incident Workspace',
categories: [
{
$id: Now.ID['incidents_category'],
title: 'Incidents',
order: 10,
lists: [
{
$id: Now.ID['incidents_open'],
title: 'Open',
order: 10,
condition: 'active=true^EQ',
table: 'incident',
columns: 'number,short_description,priority,state',
applicabilities: [
{
$id: Now.ID['incidents_open_applicability'],
applicability: applicability
}
]
}
]
}
]
});
// 3. Create workspace
const incidentWorkspace = Workspace({
$id: Now.ID['incident_management_workspace'],
title: 'Incident Management',
path: 'incident-management',
tables: ['incident', 'user'],
listConfig: incidentListConfig
});Integrating with Dashboard (par_dashboard)
import { Dashboard } from '@servicenow/sdk/core';
Dashboard({
$id: Now.ID['my_dashboard'],
name: 'My Dashboard',
tabs: [
// ... tabs configuration
],
visibilities: [
{
$id: Now.ID['my_dashboard_visibility'],
experience: myWorkspace // Reference to Workspace object
}
],
permissions: []
});Sla
Add support for ServiceNow SLA definitions (contract_sla)
Example:
// Basic SLA with user specified duration
Sla({
$id: Now.ID['incident-p1-response'],
name: 'P1 Incident Response',
table: 'incident',
duration: Duration({ hours: 1 }),
schedule: 'b1992362eb601100fcfb858ad106fe16',
conditions: {
start: 'priority=1',
stop: 'state=6',
},
})✨ New Features & Enhancements
Trusted Modules
A new trustedModules property has been added to now.config.json.
This property allows third-party module dependencies to be explicitly designated as trusted for Glide code execution. It enables a more standard Node.js–style dependency model, allowing shared sys modules to be developed, packaged, and shared as dependencies—without requiring distribution through a separate ServiceNow application.
Example:
// Trust all packages that are in the @mycompany organization. NOTE: wildcard * only works with organization name prefix.
{
"trustedModules": ["@mycompany/*"]
}
// Trust an explicit package by name
{
"trustedModules": ["package-name"]
}Type Checking for UI Builds
UI builds using TypeScript now perform diagnostic validation during the build phase.
.tsand.tsxfiles are type-checked- Build failures occur when TypeScript errors are detected
- Improves reliability before deployment
Credential Storage Changes
keytar has been replaced with @napi-rs/keyring due to deprecation of keytar, maintenance, and compatibility issues.
Note for Windows users: Existing stored credentials will re-authentication after upgrading due to storage changes
Performance Improvements
Internal optimizations to the build and transform phases deliver:
- ~30–40% reduction in heap allocation
- Faster build times for large projects (100s of files)
Performance work will continue in future releases, as we aim to drastically bring down build and transform times!
Improve Error Diagnostics
Expose missing mandatory properties when using the Record API when using the Fluent Language Extension
✅ Summary
Version 4.3.0 delivers a major step forward in Fluent-based development with workflow automation, stronger type safety, improved performance, and expanded platform coverage.
We look forward to continued iteration and feedback in upcoming releases.
For more comprehensive samples be sure to check the sdk-examples repository.
For help or support please visit the SDK Github discussions