business-rule-patterns
Original:🇺🇸 English
Translated
This skill should be used when the user asks to "create a business rule", "before insert", "after update", "async business rule", "business rule not working", "current vs previous", or any Business Rule development.
1installs
Sourcegroeimetai/snow-flow
Added on
NPX Install
npx skill4agent add groeimetai/snow-flow business-rule-patternsTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Business Rule Best Practices for ServiceNow
Business Rules are server-side scripts that execute when records are displayed, inserted, updated, or deleted.
When to Use Each Type
| Type | Timing | Use Case | Performance Impact |
|---|---|---|---|
| Before | Before database write | Validate, modify current record | Low |
| After | After database write | Create related records, notifications | Medium |
| Async | Background (after commit) | Heavy processing, integrations | None (background) |
| Display | When form loads | Modify form display, set defaults | Low |
Available Objects
javascript
// In Business Rules, these are always available:
current // The record being operated on
previous // The record BEFORE changes (update/delete only)
gs // GlideSystem utilitiesBefore Business Rules
Use for validation and field manipulation:
javascript
// Prevent update if condition not met
(function executeRule(current, previous) {
if (current.state == 7 && previous.state != 6) {
current.setAbortAction(true);
gs.addErrorMessage('Must resolve before closing');
}
})(current, previous);javascript
// Auto-populate fields
(function executeRule(current, previous) {
if (current.isNewRecord()) {
current.setValue('caller_id', gs.getUserID());
current.setValue('opened_by', gs.getUserID());
}
})(current, previous);Never do in Before rules:
- Call (causes recursion!)
current.update() - Query other tables (keep it fast)
- External API calls
After Business Rules
Use for related record operations:
javascript
// Create child record when priority is P1
(function executeRule(current, previous) {
if (current.priority.changesTo(1)) {
var task = new GlideRecord('task');
task.initialize();
task.setValue('short_description', 'P1 Follow-up: ' + current.number);
task.setValue('parent', current.sys_id);
task.insert();
}
})(current, previous);javascript
// Update parent record
(function executeRule(current, previous) {
var parent = new GlideRecord('problem');
if (parent.get(current.problem_id)) {
parent.setValue('related_incidents', parent.related_incidents + 1);
parent.update();
}
})(current, previous);Async Business Rules
Use for heavy processing that shouldn't block the transaction:
javascript
// External integration
(function executeRule(current, previous) {
var integrator = new ExternalSystemIntegration();
integrator.syncIncident(current.sys_id);
})(current, previous);javascript
// Send custom notification
(function executeRule(current, previous) {
gs.eventQueue('incident.priority.high', current, current.assigned_to, gs.getUserID());
})(current, previous);Useful Methods
current Methods
javascript
current.isNewRecord() // True if insert
current.isValidRecord() // True if record exists
current.getValue('field') // Get field value
current.setValue('field', val) // Set field value
current.setAbortAction(true) // Cancel the operation
current.operation() // 'insert', 'update', 'delete'
current.isActionAborted() // Check if abortedField Change Detection
javascript
current.priority.changes() // Field changed (any value)
current.priority.changesTo(1) // Changed TO this value
current.priority.changesFrom(3) // Changed FROM this value
current.priority.nil() // Field is emptyprevious Comparisons
javascript
// Check if field was modified
if (current.state != previous.state) {
gs.info('State changed from ' + previous.state + ' to ' + current.state);
}
// Check specific change
if (current.assigned_to.changes() && !previous.assigned_to.nil()) {
gs.info('Reassignment occurred');
}Condition Examples
Use conditions to limit when the rule runs:
| Condition | Meaning |
|---|---|
| Only active records |
| Only on insert |
| Only when priority changes |
| Only for admins |
| Only when unassigned |
Performance Best Practices
- Use conditions - Limit when the rule runs
- Keep Before rules fast - No queries if possible
- Use Async for integrations - Don't block transactions
- Avoid Display rules - Slows form load
- Set Order - Lower numbers run first (100-500 range)
- Check "when to run" - insert, update, delete, query
Common Patterns
Auto-Assignment
javascript
// Before Insert/Update
if (current.assignment_group.changes() && !current.assignment_group.nil()) {
var members = new GroupMembers(current.assignment_group);
current.assigned_to = members.getNextAvailable();
}Cascade Updates
javascript
// After Update
if (current.state.changesTo(7)) { // Closed
var tasks = new GlideRecord('task');
tasks.addQuery('parent', current.sys_id);
tasks.addQuery('state', '!=', 7);
tasks.query();
while (tasks.next()) {
tasks.setValue('state', 7);
tasks.update();
}
}