ServiceNow Business Rules - Complete
Learning Guide
Table of Contents
1. What are Business Rules?
2. Core Concepts
3. When to Execute
4. Script Structure
5. Best Practices
6. Common Patterns
7. Performance Optimization
8. Testing & Debugging
9. Advanced Topics
What are Business Rules?
Business Rules are server-side scripts that execute when records are queried, updated,
inserted, or deleted. They are the backbone of automation in ServiceNow.
Key Characteristics
Execute on the server (not client-side)
Run automatically based on conditions
Can modify current record or related records
Support both synchronous and asynchronous execution
Common Use Cases
Data validation and enforcement
Auto-population of fields
Workflow automation
Calculations and computations
Email notifications
Integration triggers
Core Concepts
1. The current Object
Represents the current record being processed.
// Accessing fields
var priority = [Link];
var caller = current.caller_id.getDisplayValue();
// Setting fields
current.assignment_group = 'Hardware Support';
[Link] = 2; // In Progress
// Checking if field is empty
if (current.assigned_to.nil()) {
// Field is empty
}
2. The previous Object
Represents the record before changes (only in Update operations).
// Check if state changed
if ([Link] != [Link]) {
[Link]('State changed from ' + [Link] + ' to ' +
[Link]);
}
// Null in Insert operations and async rules
if (previous) {
// Safe to use previous
}
3. GlideRecord
Used to query and manipulate database records.
// Query records
var gr = new GlideRecord('incident');
[Link]('active', true);
[Link]('priority', 1);
[Link]();
while ([Link]()) {
// Process each record
[Link]('Incident: ' + [Link]);
}
// Get single record
var user = new GlideRecord('sys_user');
if ([Link]('user_name', 'admin')) {
[Link]('Admin email: ' + [Link]);
}
// Insert record
var task = new GlideRecord('sc_task');
[Link]();
task.short_description = 'New task';
task.assignment_group = 'Service Desk';
[Link]();
// Update record
var inc = new GlideRecord('incident');
if ([Link](incidentId)) {
[Link] = 6;
inc.close_notes = 'Resolved';
[Link]();
}
4. GlideSystem (gs)
Global utility object for system functions.
// User information
var currentUser = [Link]();
var userName = [Link]();
var userDisplayName = [Link]();
// Messages
[Link]('Success!');
[Link]('Error occurred');
// Date/Time
var now = [Link]();
var yesterday = [Link](1);
var lastWeek = [Link](1);
// Properties
var maxAttachments = [Link]('[Link]', '10');
// Logging
[Link]('Information log');
[Link]('Warning log');
[Link]('Error log');
[Link]('Debug log');
// Date difference
var diff = [Link](startDate, endDate, true); // in seconds
When to Execute
Timing Options
When Description Use Cases current previous
Before database Validation, set field values, Yes (update
before Yes
operation prevent save only)
After database Notifications, related records, Yes (update
after Yes
operation workflows only)
Asynchronous
async Heavy processing, external calls Yes No
(queued)
display When form loads Display-only logic (rarely used) Yes No
Operation Checkboxes
☑ insert - When new record is created
☑ update - When existing record is modified
☐ delete - When record is deleted
☐ query - When record is queried (use sparingly!)
Execution Flow Example
// BEFORE rules run first
// - Validate data
// - Set calculated fields
// - Prevent save if needed
// DATABASE OPERATION occurs
// AFTER rules run next
// - Trigger workflows
// - Send notifications
// - Update related records
// ASYNC rules run in background
// - Heavy computations
// - External API calls
Script Structure
Basic Template
(function executeRule(current, previous /*null when async*/) {
// Your business logic here
})(current, previous);
Before Insert Example
(function executeRule(current, previous) {
// Auto-assign based on category
if ([Link] == 'hardware') {
current.assignment_group.setValue('Hardware Support');
} else if ([Link] == 'software') {
current.assignment_group.setValue('Software Support');
}
// Set default priority if empty
if ([Link]()) {
[Link] = 4;
}
})(current, previous);
Before Update with Validation
(function executeRule(current, previous) {
// Prevent closing without resolution notes
if ([Link] == 7 && current.close_notes == '') {
[Link]('Close notes are required');
[Link]('Cannot close without notes');
[Link](true);
}
// Prevent priority decrease on high-impact incidents
if ([Link] == 1 && [Link] > [Link]) {
[Link]('Cannot decrease priority on high-impact
incidents');
[Link] = [Link];
}
})(current, previous);
After Update with Notifications
(function executeRule(current, previous) {
// Notify when state changes to resolved
if ([Link] == 6 && [Link] != 6) {
[Link]('[Link]', current, current.caller_id,
current.assignment_group);
// Add comment
[Link] = 'Incident resolved. User notified via email.';
[Link](); // Safe in after rules
}
})(current, previous);
Async Example
(function executeRule(current, previous) {
// Heavy operation - run asynchronously
// Call external API
try {
var request = new sn_ws.RESTMessageV2();
[Link]('[Link]
[Link]('POST');
[Link]([Link]({
incident: [Link](),
description: current.short_description.toString()
}));
var response = [Link]();
var responseBody = [Link]();
// Update incident with response
var inc = new GlideRecord('incident');
if ([Link](current.sys_id)) {
inc.work_notes = 'API Response: ' + responseBody;
[Link]();
}
} catch (ex) {
[Link]('API call failed: ' + [Link]);
}
})(current, previous);
Best Practices
1. Use Conditions to Limit Execution
Condition Builder:
Priority is 1
AND State is New
Advanced Condition:
[Link]() == 'insert' ||
([Link]() && [Link] <= 2)
2. Avoid Recursive Updates
// ❌ BAD - Can cause infinite loop
(function executeRule(current, previous) {
[Link] = 1;
[Link](); // This triggers the rule again!
})(current, previous);
// ✅ GOOD - Use before rules for field changes
(function executeRule(current, previous) {
[Link] = 1;
// No update() needed - changes saved automatically
})(current, previous);
// ✅ GOOD - Check if already updated
(function executeRule(current, previous) {
if (!current.u_already_processed) {
current.u_already_processed = true;
// Do processing
[Link]();
}
})(current, previous);
3. Order Matters
Set the Order field (100, 200, 300...) to control execution sequence.
Order 100: Validate data
Order 200: Calculate fields
Order 300: Set assignment
4. Use Script Includes for Reusable Logic
// Script Include: IncidentUtils
var IncidentUtils = [Link]();
[Link] = {
initialize: function() {
},
getAssignmentGroup: function(category) {
var mapping = {
'hardware': 'Hardware Support',
'software': 'Software Support',
'network': 'Network Operations'
};
return mapping[category] || 'Service Desk';
},
type: 'IncidentUtils'
};
// Business Rule using Script Include
(function executeRule(current, previous) {
var utils = new IncidentUtils();
var group = [Link]([Link]);
current.assignment_group.setValue(group);
})(current, previous);
5. Performance Tips
// ✅ GOOD - Query once
var gr = new GlideRecord('incident');
[Link]('assignment_group', groupId);
[Link]();
var count = [Link]();
// ❌ BAD - Query in loop
for (var i = 0; i < [Link]; i++) {
var gr = new GlideRecord('incident'); // Creates new query each time
[Link](items[i]);
}
// ✅ GOOD - Use GlideAggregate for counts
var agg = new GlideAggregate('incident');
[Link]('assignment_group', groupId);
[Link]('COUNT');
[Link]();
if ([Link]()) {
var count = [Link]('COUNT');
}
6. Error Handling
(function executeRule(current, previous) {
try {
// Risky operation
var result = performComplexCalculation(current);
current.u_calculated_value = result;
} catch (ex) {
[Link]('Business Rule Error: ' + [Link]);
[Link]('An error occurred. Please contact support.');
[Link](true);
}
})(current, previous);
Common Patterns
Pattern 1: Auto-Assignment
(function executeRule(current, previous) {
if (current.assignment_group.nil() && [Link]) {
var mapping = {
'hardware': 'Hardware Support',
'software': 'Application Support',
'network': 'Network Team',
'database': 'Database Team'
};
var group = mapping[[Link]()];
if (group) {
current.assignment_group.setDisplayValue(group);
}
}
})(current, previous);
Pattern 2: Cascade Updates
(function executeRule(current, previous) {
// When parent closes, close all child tasks
if ([Link] == 3 && [Link] != 3) {
var tasks = new GlideRecord('sc_task');
[Link]('request_item', current.sys_id);
[Link]('state', '!=', 3);
[Link]();
while ([Link]()) {
[Link] = 3;
tasks.close_notes = 'Auto-closed with parent request';
[Link]();
}
}
})(current, previous);
Pattern 3: Field Calculation
(function executeRule(current, previous) {
// Calculate total cost
var quantity = parseFloat([Link]) || 0;
var unitPrice = parseFloat(current.unit_price) || 0;
var tax = parseFloat(current.tax_rate) || 0;
var subtotal = quantity * unitPrice;
var taxAmount = subtotal * (tax / 100);
var total = subtotal + taxAmount;
[Link] = [Link](2);
current.tax_amount = [Link](2);
[Link] = [Link](2);
})(current, previous);
Pattern 4: Conditional Workflow Launch
(function executeRule(current, previous) {
// Launch approval workflow for high-value requests
var cost = parseFloat(current.estimated_cost) || 0;
if (cost > 5000 && [Link] == 'not requested') {
[Link] = 'requested';
// Trigger workflow
var workflow = new Workflow();
[Link](
'Change Approval Workflow',
current,
'insert'
);
}
})(current, previous);
Pattern 5: Duplicate Detection
(function executeRule(current, previous) {
// Check for duplicate incidents
var duplicate = new GlideRecord('incident');
[Link]('caller_id', current.caller_id);
[Link]('category', [Link]);
[Link]('state', '!=', 7); // Not closed
[Link]('sys_created_on', '>', [Link](24));
[Link]('sys_id', '!=', current.sys_id);
[Link]();
if ([Link]()) {
[Link](
'A similar incident (' + [Link] + ') already exists.
' +
'Please check before creating a new one.'
);
[Link](true);
}
})(current, previous);
Pattern 6: Escalation
(function executeRule(current, previous) {
// Auto-escalate if SLA is breaching
if (!current.due_date.nil()) {
var now = new GlideDateTime();
var due = new GlideDateTime(current.due_date);
var hoursRemaining = [Link](now, due, true) / 3600;
if (hoursRemaining < 2 && hoursRemaining > 0) {
// Approaching breach
[Link] = 1;
[Link] = [Link](1, parseInt([Link]) - 1);
[Link](
'[Link]',
current,
current.assigned_to,
current.assignment_group.manager
);
}
}
})(current, previous);
Performance Optimization
1. Use Conditions Wisely
// ❌ BAD - Rule runs on every update
// Condition: (none)
if ([Link] == 6) {
// Do something
}
// ✅ GOOD - Rule only runs when needed
// Condition: State is 6
// Business rule executes only when condition is met
2. Avoid Query Loops
// ❌ BAD
var users = ['user1', 'user2', 'user3'];
for (var i = 0; i < [Link]; i++) {
var gr = new GlideRecord('sys_user');
[Link]('user_name', users[i]); // Query per iteration
}
// ✅ GOOD
var users = ['user1', 'user2', 'user3'];
var gr = new GlideRecord('sys_user');
[Link]('user_name', 'IN', [Link](','));
[Link]();
while ([Link]()) {
// Process all at once
}
3. Limit Query Results
var gr = new GlideRecord('incident');
[Link]('active', true);
[Link](100); // Limit results
[Link]();
4. Use GlideAggregate for Counts
// ❌ BAD
var gr = new GlideRecord('incident');
[Link]('assigned_to', userId);
[Link]();
var count = 0;
while ([Link]()) {
count++;
}
// ✅ GOOD
var agg = new GlideAggregate('incident');
[Link]('assigned_to', userId);
[Link]('COUNT');
[Link]();
if ([Link]()) {
var count = [Link]('COUNT');
}
5. Async for Heavy Operations
Use async business rules for:
External API calls
Complex calculations
Processing large datasets
Operations that don't need immediate results
Testing & Debugging
1. Logging
(function executeRule(current, previous) {
[Link]('BR: Processing incident ' + [Link]);
[Link]('Priority: ' + [Link]);
[Link]('Category: ' + [Link]);
// Log object details
[Link]('Current: ' + [Link]({
number: [Link](),
priority: [Link](),
state: [Link]()
}));
})(current, previous);
2. Using Scripts - Background
Navigate to System Definition > Scripts - Background
// Test your business rule logic
var inc = new GlideRecord('incident');
[Link]('INC0010001');
// Simulate the logic
if ([Link] == 6) {
[Link]('Incident is resolved');
}
[Link]('Priority: ' + [Link]);
[Link]('Category: ' + [Link]);
3. Check Execution
System Logs > System Log > All
Filter by Source = Business Rule
Check execution time and errors
4. Debug Mode
Enable debug logging:
[Link]('debug', '[Link]');
5. Common Debugging Techniques
(function executeRule(current, previous) {
// Check if running in correct context
[Link]('Is Insert: ' + [Link]());
[Link]('Is Update: ' + ![Link]());
// Check field changes
if (previous) {
[Link]('State changed: ' + [Link]());
[Link]('Old state: ' + [Link]);
[Link]('New state: ' + [Link]);
}
// Verify conditions
[Link]('Assignment group empty: ' + current.assignment_group.nil());
})(current, previous);
Advanced Topics
1. GlideDateTime Manipulation
// Create date objects
var gdt = new GlideDateTime();
var specificDate = new GlideDateTime('2024-01-15 10:30:00');
// Add/subtract time
[Link](7);
[Link](2);
[Link](30);
[Link](86400000); // milliseconds
// Compare dates
if ([Link](specificDate)) {
// gdt is later
}
if ([Link](specificDate)) {
// gdt is earlier
}
// Format
var displayValue = [Link]();
var internalValue = [Link]();
// Business hours calculation
var schedule = new GlideSchedule('8x5'); // Business hours schedule
var duration = [Link](startDate, endDate);
2. Working with Reference Fields
// Get referenced record details
var assignedUser = current.assigned_to.getRefRecord();
if (assignedUser) {
var userEmail = [Link]();
var userManager = [Link]();
}
// Set reference by sys_id
current.assignment_group.setValue(groupSysId);
// Set reference by display value
current.assignment_group.setDisplayValue('Service Desk');
// Check if reference is empty
if (current.assigned_to.nil()) {
// Reference is empty
}
3. GlideRecord Advanced Queries
// OR conditions
var gr = new GlideRecord('incident');
var qc = [Link]('priority', 1);
[Link]('priority', 2);
[Link]();
// IN operator
[Link]('state', 'IN', '1,2,3');
// NOT IN
[Link]('state', 'NOT IN', '6,7,8');
// NULL checks
[Link]('assigned_to');
[Link]('assignment_group');
// Date queries
[Link]('sys_created_on', '>=', [Link](7));
[Link]('due_date', '<', [Link]());
// Encoded queries (for complex conditions)
[Link]('priority=1^ORpriority=2^state!=7');
4. Script Include Integration
// Create Script Include: AssignmentHelper
var AssignmentHelper = [Link]();
[Link] = {
initialize: function() {
[Link] = 'Service Desk';
},
getOptimalAssignee: function(incident) {
// Complex logic to find best assignee
var group = incident.assignment_group.toString();
var members = new GlideRecord('sys_user_grmember');
[Link]('group', group);
[Link]();
var lowestWorkload = 999;
var optimalUser = null;
while ([Link]()) {
var workload =
this._calculateWorkload([Link]());
if (workload < lowestWorkload) {
lowestWorkload = workload;
optimalUser = [Link]();
}
}
return optimalUser;
},
_calculateWorkload: function(userId) {
var agg = new GlideAggregate('incident');
[Link]('assigned_to', userId);
[Link]('state', '<', 6);
[Link]('COUNT');
[Link]();
if ([Link]()) {
return parseInt([Link]('COUNT'));
}
return 0;
},
type: 'AssignmentHelper'
};
// Use in Business Rule
(function executeRule(current, previous) {
if (current.assigned_to.nil() && !current.assignment_group.nil()) {
var helper = new AssignmentHelper();
var assignee = [Link](current);
if (assignee) {
current.assigned_to = assignee;
}
}
})(current, previous);
5. Event Management
// Queue an event
[Link](
'[Link]', // Event name
current, // Record
current.assigned_to, // parm1
current.assignment_group // parm2
);
// Process event in Business Rule or Script Action
// When: Event fires = [Link]
(function executeRule(current, previous) {
var assignedTo = event.parm1; // User who was assigned
var group = event.parm2; // Assignment group
// Send notification
var email = new GlideEmailOutbound();
[Link]('New incident assigned: ' + [Link]);
[Link]('You have been assigned incident ' + [Link]);
[Link](assignedTo);
[Link]();
})(current, previous);
6. Complex Conditional Logic
(function executeRule(current, previous) {
// Multi-factor decision making
var shouldEscalate = false;
var escalationReasons = [];
// Check age
var ageHours = [Link](current.sys_created_on, [Link](),
true) / 3600;
if (ageHours > 24 && [Link] < 6) {
shouldEscalate = true;
[Link]('Open for ' + [Link](ageHours) + '
hours');
}
// Check reassignment count
if (current.reassignment_count > 2) {
shouldEscalate = true;
[Link]('Reassigned ' + current.reassignment_count +
' times');
}
// Check VIP status
if (current.caller_id.vip == true) {
shouldEscalate = true;
[Link]('VIP user');
}
// Check CI criticality
if (!current.cmdb_ci.nil()) {
var ci = current.cmdb_ci.getRefRecord();
if (ci.u_criticality == 'critical') {
shouldEscalate = true;
[Link]('Critical CI affected');
}
}
if (shouldEscalate) {
[Link] = 1;
[Link] = [Link](1, parseInt([Link]) - 1);
current.work_notes = 'AUTO-ESCALATED: ' + [Link](',
');
// Notify management
[Link]('[Link]', current);
}
})(current, previous);
Learning Path
Beginner Level
1. ✅ Understand current and previous objects
2. ✅ Learn When to execute (before/after/async)
3. ✅ Practice basic field manipulation
4. ✅ Write simple validation rules
5. ✅ Use conditions to limit execution
Intermediate Level
1. ✅ Master GlideRecord queries
2. ✅ Implement complex conditional logic
3. ✅ Work with reference fields
4. ✅ Use GlideDateTime for date calculations
5. ✅ Create Script Includes for reusable code
6. ✅ Implement error handling
Advanced Level
1. ✅ Optimize for performance
2. ✅ Implement pattern matching algorithms
3. ✅ Build intelligent automation
4. ✅ Integrate with external systems (REST/SOAP)
5. ✅ Design scalable, maintainable solutions
6. ✅ Handle complex business scenarios
Quick Reference Card
Essential Methods
// Current record
[Link]('field_name')
[Link]('field_name', value)
[Link]()
[Link]()
[Link](true)
// GlideRecord
[Link]('field', 'value')
[Link]()
[Link]()
[Link]()
[Link]()
[Link]()
[Link]()
// GlideSystem
[Link]()
[Link]('text')
[Link]('text')
[Link]()
[Link](n)
[Link](date1, date2, true)
[Link]('event_name', record)
// GlideDateTime
var gdt = new GlideDateTime()
[Link](n)
[Link](n)
[Link](otherDate)
[Link](otherDate)
Common Patterns
// Check if insert
if ([Link]()) { }
// Check if update
if (![Link]()) { }
// Check field changed
if (current.field_name.changes()) { }
// Check empty
if (current.field_name.nil()) { }
// Safe previous check
if (previous && [Link] != [Link]) { }
Practice Exercises
Exercise 1: Auto-Assignment
Create a business rule that assigns incidents based on category:
Hardware → Hardware Support
Software → Application Team
Network → Network Operations
Exercise 2: Validation
Create a rule that prevents closing an incident without:
Close notes
Resolution code
Actual end time
Exercise 3: Escalation
Create a rule that escalates incidents when:
Open for more than 48 hours
Priority is 1 or 2
Not yet resolved
Exercise 4: Cascade Update
Create a rule that when a change request is approved, automatically approves all child tasks.
Exercise 5: Duplicate Detection
Create a rule that prevents creating duplicate incidents from the same user with the same
short description within 24 hours.
Resources
Official Documentation
ServiceNow Product Documentation
Developer Portal
Community Forums
Now Learning Platform
Practice Environments
Personal Developer Instance ([Link])
ServiceNow Simulator
Practice Labs
Tips for Success
1. Start simple and build complexity gradually
2. Always test in a development instance
3. Use logging extensively for debugging
4. Read existing business rules to learn patterns
5. Join ServiceNow community forums
6. Take ServiceNow certification courses
Remember: Good business rules are:
✅ Simple and focused
✅ Well-documented
✅ Performance-optimized
✅ Easy to maintain
✅ Properly tested
1. Auto-Populate Assignment Group
When: Before insert Purpose: Automatically set assignment group based on category
(function executeRule(current, previous /*null when async*/) {
if ([Link] == 'hardware') {
current.assignment_group.setValue('Hardware Support Team');
} else if ([Link] == 'software') {
current.assignment_group.setValue('Software Support Team');
} else if ([Link] == 'network') {
current.assignment_group.setValue('Network Operations');
})(current, previous);
2. Prevent Closure Without Resolution
When: Before update Purpose: Validate required fields before closing
(function executeRule(current, previous /*null when async*/) {
if ([Link] == 7 && current.close_notes == '') { // 7 = Closed
[Link]('Close notes are required to close this incident');
[Link]('Cannot close without resolution notes');
[Link](true);
})(current, previous);
3. Calculate SLA Due Date
When: Before insert Purpose: Set due date based on priority
(function executeRule(current, previous /*null when async*/) {
var gdt = new GlideDateTime();
if ([Link] == 1) {
[Link](4); // Critical - 4 hours
} else if ([Link] == 2) {
[Link](8); // High - 8 hours
} else if ([Link] == 3) {
[Link](3); // Medium - 3 days
} else {
[Link](7); // Low - 7 days
current.due_date = gdt;
})(current, previous);
4. Send Email Notification on Status Change
When: After update Purpose: Notify requester when ticket is resolved
(function executeRule(current, previous /*null when async*/) {
if ([Link] == 6 && [Link] != 6) { // 6 = Resolved
var email = new GlideEmailOutbound();
[Link]('Your incident ' + [Link] + ' has been
resolved');
[Link]('Your incident has been resolved. Resolution: ' +
current.close_notes);
[Link](current.caller_id.email);
[Link]();
})(current, previous);
5. Auto-Escalate Overdue Tickets
When: After insert/update (scheduled daily) Purpose: Escalate tickets past due date
(function executeRule(current, previous /*null when async*/) {
var now = new GlideDateTime();
var due = new GlideDateTime(current.due_date);
if ([Link] != 6 && [Link] != 7 && [Link](due)) {
[Link] = 1; // Escalated
[Link] = [Link](1, [Link] - 1); // Increase priority
[Link] = 'Auto-escalated due to SLA breach';
[Link]();
})(current, previous);
6. Prevent Duplicate Records
When: Before insert Purpose: Check for existing tickets from same user
(function executeRule(current, previous /*null when async*/) {
var gr = new GlideRecord('incident');
[Link]('caller_id', current.caller_id);
[Link]('short_description', current.short_description);
[Link]('state', '!=', 7); // Not closed
[Link]('sys_created_on', '>', [Link](1)); // Within 24 hours
[Link]();
if ([Link]()) {
[Link]('A similar incident already exists: ' +
[Link]);
[Link](true);
})(current, previous);
7. Update Related Records
When: After update Purpose: Close related tasks when parent closes
(function executeRule(current, previous /*null when async*/) {
if ([Link] == 7 && [Link] != 7) { // Closed
var tasks = new GlideRecord('sc_task');
[Link]('request_item', current.sys_id);
[Link]('state', '!=', 3); // Not closed
[Link]();
while ([Link]()) {
[Link] = 3; // Closed
tasks.close_notes = 'Auto-closed with parent request item';
[Link]();
})(current, previous);
Best Practices:
Use Before rules for validation and setting values
Use After rules for notifications and related record updates
Keep business rules simple and focused on one task
Use conditions to limit when the rule runs
Avoid complex queries in synchronous rules
Consider using Script Includes for reusable logic
1. Asynchronous Business Rule — Auto-create Change
Task
Use Case: When a Change Request moves to Implementation, automatically create a Change
Task after the record is committed (async for performance).
(function executeRule(current, previous) {
// Run only when state changes to "Implementation"
if ([Link]('implementation')) {
// Create Change Task asynchronously
var task = new GlideRecord('change_task');
[Link]();
task.change_request = current.sys_id;
task.short_description = 'Perform Implementation activities';
task.assigned_to = current.assigned_to;
[Link]();
[Link]('Change Task created for Change Request: ' +
[Link]);
})(current, previous);
Trigger: after update (set Advanced → Execute asynchronously)
Purpose: Offloads secondary operations to background for faster UI
response.
2. Conditional Data Update Using GlideAggregate
Use Case: Update Problem record with total number of open incidents linked to it whenever
an Incident’s state changes.
(function executeRule(current, previous) {
if (current.problem_id && [Link]()) {
var agg = new GlideAggregate('incident');
[Link]('COUNT');
[Link]('problem_id', current.problem_id);
[Link]('state', '!=', 7); // not Closed
[Link]();
if ([Link]()) {
var prob = new GlideRecord('problem');
if ([Link](current.problem_id)) {
prob.u_open_incident_count = [Link]('COUNT');
[Link]();
})(current, previous);
Trigger: after update
Table: incident
Purpose: Maintains real-time metrics using GlideAggregate for
performance.
3. Auto-sync Between Two Tables (Custom Integration)
Use Case: When an Asset is updated, automatically sync key fields to Custom Hardware
Inventory table.
(function executeRule(current, previous) {
var inv = new GlideRecord('u_hardware_inventory');
[Link]('u_asset', current.sys_id);
[Link]();
if ([Link]()) {
inv.u_serial_number = current.serial_number;
inv.u_model = [Link];
inv.u_location = [Link];
[Link]();
} else {
[Link]();
inv.u_asset = current.sys_id;
inv.u_serial_number = current.serial_number;
inv.u_model = [Link];
inv.u_location = [Link];
[Link]();
})(current, previous);
Trigger: after update
Table: alm_asset
Purpose: Keeps custom integration tables synchronized.
. Restrict Update Based on Workflow Stage
Use Case: In a Change Request, prevent users from updating Risk and Impact Analysis once
it’s approved by CAB.
(function executeRule(current, previous) {
// Check if CAB approved
if (current.u_cab_approved == true &&
current.u_risk_impact.changes()) {
[Link]("Risk and Impact analysis cannot be modified
after CAB approval.");
[Link](true);
})(current, previous);
Best Practices Summary
Area Recommendation
Performance Use async rules for post-processing tasks.
Query Optimization Always filter GlideRecord queries precisely (use indexed fields).
Use [Link]() and [Link](true)
Error Handling
for user-safe errors.
Avoid Loops on
Always check for field changes using .changes() or .changesTo().
Updates
Debugging Use [Link]() during testing (not in production).
Optional Enhancement — Restrict Edits Post-Approval
Table: change_request
When: before update
(function executeRule(current, previous) {
if (previous.u_approval_status == 'Approved' &&
current.short_description.changes()) {
[Link]("Approved Change Requests cannot be
modified.");
[Link](true);
})(current, previous);