What It Is

Actions are atomic, reusable automation components that perform specific operations within Flow Designer. Each Action encapsulates a single logical operation — creating a record, sending an email, calling a REST endpoint, or executing custom script logic — and exposes a standardized interface with defined inputs and outputs. Actions solve the fundamental problem of automation reusability by packaging common operations into components that can be used across multiple flows, subflows, and even different applications without duplicating configuration or code.

Architecturally, Actions live within the IntegrationHub application (com.glideapp.integrationhub) as part of ServiceNow's automation layer. They're stored in the sys_hub_action_type_base table with their input/output definitions in sys_hub_action_input and sys_hub_action_output. Actions execute within the Flow Engine runtime environment, which provides transaction management, error handling, and data context propagation between flow steps. Unlike Business Rules or Script Includes that operate at the database or application layer, Actions operate specifically within the Flow Designer execution context.

The underlying data model treats Actions as templates that get instantiated when used in flows. Each Action usage creates a sys_hub_step_action record that references the Action definition and stores the specific input values for that instance. The execution environment provides each Action with a StepResult object for managing outputs and an ActionInputs object for accessing inputs, along with full access to server-side ServiceNow APIs. Actions can be synchronous (blocking flow execution until complete) or asynchronous (allowing flows to continue while the Action executes in the background), with the execution model determined by the Action's implementation.

You cannot function without Actions in any meaningful automation scenario because they represent the actual work being performed — flows themselves are just orchestration containers. Every integration with external systems, every record manipulation, every notification sent requires an Action to perform the operation. Without Actions, Flow Designer would be an empty orchestration shell with no capability to interact with ServiceNow data or external systems. Complex business processes that require multi-step approval workflows, automated ticket routing based on configuration management database relationships, or integration with enterprise systems like Active Directory or third-party monitoring tools all depend entirely on Actions to perform the individual operations.

Platform developers typically create custom Actions when existing system Actions don't meet requirements, using ServiceNow Studio or App Engine Studio to build Actions with custom script logic, complex input validation, or specialized integrations. System administrators primarily consume existing Actions by configuring them within flows, mapping inputs from flow data, and handling outputs in subsequent flow steps. Platform owners govern Action availability through application scoping and determine which Actions are available to different development teams. The relationship between these roles has shifted significantly — administrators now handle much more complex automation scenarios that previously required custom development, while developers focus on building reusable Action components rather than point solutions.

Recent ServiceNow releases have introduced significant changes to Action capabilities and behavior. Vancouver added enhanced error handling with try-catch semantics and improved debugging through step execution logs. Washington introduced Action Designer improvements with better input validation and output mapping capabilities. Xanadu brought asynchronous Action support and enhanced integration with RPA Hub, allowing Actions to trigger and monitor robotic process automation workflows. The most significant change is the introduction of Action Analytics in recent releases, providing visibility into Action performance, failure rates, and usage patterns across the platform.

Where to Find and Configure It

Navigate to Process Automation > Flow Designer to access the primary interface where you build and configure Actions within flows. Use Process Automation > Action Designer to create custom Actions or modify existing ones with script-based logic. Access System Definition > Tables and filter for sys_hub_action_type_base to view the underlying Action definitions and their metadata directly.

In Studio, navigate to Flow Logic > Actions within your application scope to create and manage application-specific Actions. App Engine Studio provides Actions through Logic and automation > Actions with a simplified interface for citizen developers. The All > IntegrationHub > Actions menu provides the complete catalog of available Actions across all applications and scopes, including system Actions and custom Actions from other applications.

See Actions in active use by navigating to Process Automation > Executions where individual Action executions appear as step entries with their input values, output results, and execution status. Monitor Action performance through Process Automation > Analytics to view usage patterns and failure rates across your Action implementations. Scoped applications can only access Actions that are either defined within their scope or published from the global scope, while global scope has access to all Actions across the platform — this scoping affects which Actions appear in the Flow Designer palette and Action Designer catalog.

How It Works Step by Step

Actions execute within the Flow Engine's managed runtime environment, which provides transaction boundaries, error handling, and data context management. When a flow reaches an Action step, the Flow Engine instantiates the Action definition with the specific input values configured for that step, creating an execution context that includes access to ServiceNow server-side APIs, the flow's data pill values, and any inherited security context from the triggering user or system account. The Action's script logic executes within this context, with any database operations participating in the flow's overall transaction scope.

Input validation occurs before script execution, ensuring all required inputs are present and conform to their defined data types. The Flow Engine passes validated inputs to the Action through the inputs parameter, while providing a steps object for setting output values that subsequent flow steps can consume. Error handling follows a structured approach where unhandled exceptions terminate the flow execution, while Actions can explicitly set error outputs to trigger alternative flow paths.

Actions inherit the security context and scope restrictions of their containing flow, meaning database operations respect Access Control Lists, Business Rules, and field-level security exactly as if the triggering user performed them directly. Flow data pills from previous steps remain accessible throughout Action execution, and any records created or modified by the Action immediately become available as output data pills for subsequent flow steps without requiring additional queries.

Free Newsletter

Enjoying this? Get one deep-dive per week.

Join 1,000+ ServiceNow pros — scripts, GlideRecord patterns, Flow Designer techniques, and career moves. Free.

No spam · Unsubscribe anytime

The Execution Order

  1. Flow Engine validates all Action inputs against their defined data types and required field constraints
  2. Engine creates execution context with validated inputs, flow data pills, and user security context
  3. Action script executes with full access to ServiceNow server-side APIs and current transaction
  4. Any database operations participate in the flow's transaction with full Business Rule execution
  5. Action sets output values through the steps parameter for use by subsequent flow steps
  6. Engine validates output values against defined output specifications
  7. Execution status and outputs are logged to sys_hub_step_log for debugging and monitoring
  8. Flow execution continues to next step with Action outputs available as data pills
Custom Action Script
(function execute(inputs, outputs) {
    // Input validation and processing
    var incidentNumber = inputs.incident_number;
    var assignmentGroup = inputs.assignment_group;
    
    // Query for the incident record
    var incident = new GlideRecord('incident');
    incident.addQuery('number', incidentNumber);
    incident.query();
    
    if (incident.next()) {
        // Update incident assignment
        incident.assignment_group = assignmentGroup;
        incident.assigned_to = '';
        incident.state = 2; // In Progress
        incident.work_notes = 'Automatically reassigned by flow';
        incident.update();
        
        // Set outputs for subsequent flow steps
        outputs.sys_id = incident.getUniqueValue();
        outputs.updated_by = gs.getUserID();
        outputs.success = true;
    } else {
        outputs.success = false;
        outputs.error_message = 'Incident not found: ' + incidentNumber;
    }
})(inputs, outputs);

Real-World Scenarios

Creating Change Requests with CMDB Validation

Your organization requires all change requests to validate that affected Configuration Items exist in the CMDB and have active support contracts before creating the change record. Standard change creation Actions don't include this business logic validation.

CMDB Validated Change Creation
(function execute(inputs, outputs) {
    var ciSysId = inputs.configuration_item;
    var changeDescription = inputs.description;
    var requestedBy = inputs.requested_by;
    
    // Validate CI exists and has active support
    var ci = new GlideRecord('cmdb_ci');
    if (!ci.get(ciSysId) || ci.support_group.nil()) {
        outputs.success = false;
        outputs.error_message = 'CI not found or missing support group';
        return;
    }
    
    // Create change request with validated CI
    var change = new GlideRecord('change_request');
    change.initialize();
    change.short_description = 'Change for ' + ci.name;
    change.description = changeDescription;
    change.cmdb_ci = ciSysId;
    change.requested_by = requestedBy;
    change.assignment_group = ci.support_group;
    change.insert();
    
    outputs.change_sys_id = change.getUniqueValue();
    outputs.change_number = change.number.toString();
    outputs.success = true;
})(inputs, outputs);

Configure inputs for configuration_item (Reference to cmdb_ci), description (String), and requested_by (Reference to sys_user). Watch for CI reference validation — invalid references will cause the Action to fail before script execution. The support group lookup depends on your CMDB data quality, so test with CIs that lack support group assignments to ensure proper error handling.

Bulk User Notification with Template Selection

When major incidents occur, you need to notify different user groups with role-appropriate message templates — end users get simplified status updates while IT staff receive technical details. Standard notification Actions only support single template selection per execution.

Role-Based Bulk Notification
(function execute(inputs, outputs) {
    var incidentSysId = inputs.incident_sys_id;
    var notificationScope = inputs.scope; // 'end_users' or 'it_staff'
    
    // Get incident details
    var incident = new GlideRecord('incident');
    incident.get(incidentSysId);
    
    // Select appropriate user group and template
    var groupName = (notificationScope === 'end_users') ? 'End User Support' : 'Network Support';
    var templateId = (notificationScope === 'end_users') ? 'user_incident_notification' : 'technical_incident_notification';
    
    // Get group members
    var groupMembers = new GlideRecord('sys_user_grmember');
    groupMembers.addQuery('group.name', groupName);
    groupMembers.addQuery('user.active', true);
    groupMembers.query();
    
    var notifiedUsers = [];
    while (groupMembers.next()) {
        // Send notification using selected template
        gs.eventQueue('incident.notification', incident, groupMembers.user.getDisplayValue(), templateId);
        notifiedUsers.push(groupMembers.user.email.toString());
    }
    
    outputs.notification_count = notifiedUsers.length;
    outputs.notified_users = notifiedUsers.join(',');
    outputs.template_used = templateId;
})(inputs, outputs);

Set up inputs for incident_sys_id (String) and scope (Choice with options). The notification templates must exist in your Email Templates and match the IDs referenced in the script. Group membership queries can be expensive with large groups, so consider caching group member lists or limiting notification frequency to prevent performance issues during major incident scenarios.

Dynamic SLA Assignment Based on Customer Tier

Your service desk needs to automatically assign different SLA definitions to incidents based on the requesting user's customer account tier (Platinum, Gold, Silver), with escalation rules that vary by customer contract terms. Standard SLA Actions don't support dynamic SLA selection with custom business logic.

Dynamic SLA Assignment Action
(function execute(inputs, outputs) {
    var incidentSysId = inputs.incident_sys_id;
    var callerSysId = inputs.caller_id;
    
    // Get customer tier from user's account
    var user = new GlideRecord('sys_user');
    user.get(callerSysId);
    var customerTier = user.u_customer_tier.toString(); // Custom field
    
    // Map tiers to SLA definitions
    var slaMapping = {
        'platinum': '4-hour response, 24-hour resolution',
        'gold': '8-hour response, 2-day resolution', 
        'silver': '24-hour response, 5-day resolution'
    };
    
    // Get appropriate SLA definition
    var slaDefinition = new GlideRecord('contract_sla');
    slaDefinition.addQuery('name', 'CONTAINS', customerTier);
    slaDefinition.addQuery('active', true);
    slaDefinition.query();
    
    if (slaDefinition.next()) {
        // Apply SLA to incident
        var incident = new GlideRecord('incident');
        incident.get(incidentSysId);
        incident.sla_due = new GlideDateTime(slaDefinition.duration);
        incident.u_customer_tier = customerTier;
        incident.update();
        
        outputs.sla_applied = slaDefinition.name.toString();
        outputs.due_date = incident.sla_due.toString();
        outputs.success = true;
    }
})(inputs, outputs);

Configure inputs for incident_sys_id and caller_id as String inputs. This approach requires the u_customer_tier custom field on the User table and corresponding SLA definition records. SLA duration calculations will fail if your SLA definitions don't include proper duration specifications, and the mapping logic needs updating whenever new customer tiers are introduced.

⚠️

Actions execute with the security context of the flow trigger, not the Action creator. Test thoroughly with different user roles to ensure database operations don't fail due to ACL restrictions.

The Classic Mistake

⚠️

Creating custom Actions with synchronous script steps that call external APIs or perform database-intensive operations without proper error handling.

BadAction.js
// BAD: Synchronous API call in Action script step
var restMessage = new sn_ws.RESTMessageV2('External_API', 'POST');
restMessage.setEndpoint('https://api.example.com/users');
restMessage.setRequestBody(JSON.stringify({
    name: inputs.user_name,
    email: inputs.user_email
}));

var response = restMessage.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();

// No timeout handling, no retry logic, no error checking
var result = JSON.parse(responseBody);
outputs.external_id = result.id;
outputs.success = true;

This fails because Flow executions timeout after 300 seconds by default, and the entire Flow becomes unresponsive during synchronous calls. Users see Flows that appear to hang or fail with cryptic timeout errors, while ServiceNow queues up execution contexts that consume system resources. The non-obvious part is that the Action itself may succeed, but the Flow context times out, leaving the workflow in an inconsistent state where external systems are updated but ServiceNow records aren't. Flow Designer provides no visual indication of long-running synchronous operations until they fail completely.

GoodAction.js
// GOOD: Proper error handling and timeout management
try {
    var restMessage = new sn_ws.RESTMessageV2('External_API', 'POST');
    restMessage.setEndpoint('https://api.example.com/users');
    restMessage.setHttpTimeout(10000); // 10 second timeout
    restMessage.setRequestBody(JSON.stringify({
        name: inputs.user_name,
        email: inputs.user_email
    }));
    
    var response = restMessage.execute();
    var httpStatus = response.getStatusCode();
    
    if (httpStatus >= 200 && httpStatus < 300) {
        var result = JSON.parse(response.getBody());
        outputs.external_id = result.id;
        outputs.success = true;
        outputs.error_message = '';
    } else {
        outputs.success = false;
        outputs.error_message = 'API returned status: ' + httpStatus;
        gs.error('External API failed: ' + response.getBody());
    }
} catch (ex) {
    outputs.success = false;
    outputs.error_message = ex.getMessage();
    gs.error('Action script error: ' + ex.getMessage());
}
💡

Always include explicit timeout values, error outputs, and try-catch blocks in custom Action scripts. If the operation takes longer than 10 seconds, use Scheduled Script Execution or MID Server capabilities instead.

When to Use This vs Alternatives

Use Actions when you need reusable automation logic that multiple Flows will consume, especially for operations that require input validation, data transformation, or integration with external systems. Actions excel when the same business logic needs consistent execution across different workflow contexts with varying input parameters.

When Actions Are the Right Choice

Choose Actions over inline Flow logic when you need parameterized operations that will be called from 3+ different Flows, or when the logic involves complex data manipulation that would clutter Flow Designer's visual interface. Business Rules and Script Includes can't provide the same declarative input/output interface that makes Actions discoverable and maintainable within Flow Designer. Actions also provide better version control and deployment management than scattered inline scripts across multiple Flows.

When to Use Script Includes Instead

Use Script Includes when the logic needs to be called from Business Rules, UI Actions, scheduled jobs, or other server-side contexts beyond Flow Designer. Script Includes provide better performance for utility functions that don't need Flow Designer's execution context, and they're essential when the same logic must be available to both Flow-based and traditional ServiceNow automation. Actions can't be called directly from Business Rules or other script-based automation.

When You Need Both Actions and Subflows

Combine Actions with Subflows when you need reusable business processes that include both data operations and approval workflows. Actions handle the data transformation and system integration pieces, while Subflows orchestrate the multi-step business process including user interactions and decision points. This pattern works well for complex scenarios like employee onboarding where Actions manage system provisioning while Subflows handle approval routing and task assignments.

Platform Interactions & Side Effects

  • Action executions create records in sys_flow_context and sys_hub_action_step tables, with full input/output parameter logging that can expose sensitive data in execution history
  • Custom Actions bypass table-level Business Rules and ACLs when using autoSysFields: false in GlideRecord operations, potentially creating audit trail gaps
  • Action modifications trigger Update Set capture in sys_hub_action_type_base and related tables, but input/output parameter changes can break existing Flow implementations without warning
  • Actions inherit the Flow execution user's role context, which can cause permission errors when Flows are triggered by users with restricted access to tables referenced in Action scripts
  • Notifications triggered within Action scripts use the system user context, not the Flow initiator, affecting notification recipient resolution and audit records
  • REST Message calls from Actions don't respect MID Server affinity rules, always routing through the primary instance's outbound connections
  • Action execution failures don't automatically retry unless explicitly configured in the parent Flow, unlike some system Actions that have built-in retry mechanisms
  • Actions consuming Web Services from the Service Registry bypass normal rate limiting and connection pooling, potentially overwhelming external systems
  • Memory-intensive Actions can cause Flow Designer sessions to exceed heap limits, particularly when processing large data sets or file attachments in custom script steps
  • Action deletions leave orphaned references in Flow configurations, causing runtime errors that only surface when the specific Action step executes

Debugging and Troubleshooting

Action failures typically manifest as Flow executions that stop at specific steps without clear error messages, or Flows that complete but produce unexpected output values. Users report that automation "just stopped working" or produces incorrect results, while Flow execution history shows the Action step completed but with empty or null output values. The most frustrating symptom is when Actions appear to execute successfully in the Flow Designer test mode but fail in production due to user context or data differences.

Primary debugging locations include System Log > All filtered by source = Flow Designer, the Flow execution history accessible via Process Automation > Flow Designer > Executions, and the sys_hub_action_step table for detailed Action step execution data. Script errors appear as "ReferenceError" or "TypeError" messages, while permission issues show as "Access denied" errors with table and operation details. Integration failures typically log HTTP status codes and response bodies in the system log with timestamps matching the Flow execution.

Enable detailed logging by setting com.glide.hub.flow_engine.log_level to debug and use gs.info() statements in custom Action scripts to trace variable values and execution flow. Look for log entries containing "ActionStepProcessor" for Action-specific execution details, and "FlowEngine" entries for broader Flow context issues. Integration errors often appear with specific HTTP status codes like "ConnectionTimeout" or "ReadTimeout" that indicate network-level problems versus application errors.

Diagnostic Checklist:

  • Verify input parameter data types match Action input definitions, especially for date fields and reference values
  • Check user permissions for all tables and fields accessed within the Action script using the Flow initiator's role set
  • Review sys_hub_action_step records for the failing execution to see actual input/output values
  • Test the Action independently using Flow Designer's "Test" feature with known good input data
  • Validate REST Message configurations and endpoint availability if the Action performs external integrations
  • Confirm Action version matches what's deployed in the target environment using Update Set preview
  • Check system property glide.flow.max_execution_time if Actions involve long-running operations

Quick Reference

  • Actions have a 300-second default execution timeout controlled by glide.flow.max_execution_time, but individual script steps can timeout earlier based on transaction limits
  • Custom Actions can accept maximum 20 input parameters and 20 output parameters, with 255-character limits on parameter names
  • Action execution history in sys_hub_action_step is retained for 30 days by default, controlled by the "Flow Context Cleaner" scheduled job
  • Actions inherit the security context of the Flow execution user, not the Action creator, affecting table access and field visibility
  • System Actions (Create Record, Update Record) can process up to 100 records per execution, while custom Actions have no built-in batch limits
  • Action parameter values are logged in plain text in sys_hub_action_step.inputs and outputs fields, including sensitive data like passwords
  • Actions published to the Global scope cannot be modified in child applications, requiring new wrapper Actions for customization
  • REST Message calls from Actions don't support OAuth 2.0 refresh token handling, requiring manual token management in custom scripts
  • Action input parameters support dot-walking for reference fields (like caller_id.email) but not for complex object traversal or array access
  • Deleting an Action doesn't automatically update Flows that reference it, creating runtime dependencies that only break during execution