Business Rules

Update a Related Record from a Business Rule

Business rules often need to update related records when the current record changes — like updating a project status when all its tasks are complete. This guide shows you how to query the related record, update its fields, and avoid the common traps that create infinite loops or performance problems.

When manual updates create data inconsistency

Without automated updates to related records, your data gets out of sync fast. Users update an incident but forget to update the parent problem. A task gets closed but the parent request stays 'In Progress'. The people affected — end users, managers, and support teams — make decisions based on stale data. Platform admins get tickets about 'wrong' information that's technically correct but not current. Manual processes for keeping related data synchronized don't scale and create more work for everyone.

How related record updates work

A Business Rule uses GlideRecord to query and update related records after the triggering record is saved. The basic pattern is: check what changed on the current record, query the related record using the relationship field, update the target field, and save. The progression from basic to production-quality involves adding conditions to prevent unnecessary runs, using silent updates to avoid triggering cascading rules, and implementing safeguards against infinite loops. Most developers start with a simple after rule and add performance optimizations once they see how it behaves.

Making it production-ready

Once your basic rule works, the key improvements are: using setWorkflow(false) and autoSysFields(false) for silent updates that don't trigger other business rules, adding specific field change detection instead of running on every update, and implementing loop prevention when the rule might update records on the same table. Advanced implementations include bulk update handling when many records change at once, error logging for failed updates, and rollback strategies for complex multi-record transactions.

Before you start

  • admin role or business_rule_admin role
  • Understanding of table relationships and reference fields
Sourdough
Chrome Extension

Sourdough: ServiceNow Monitoring and Analytics

A Chrome extension for ServiceNow Admins and Developers with essential tools, analytics, graphs and monitoring features.

Instance HealthGraphs & ChartsAPI HealthDeveloper ToolsQuick SearchInstance Switcher
Add to Chrome

Free to install. Pro $5/month after a 14-day no-card trial.
Pro requires the ServiceNow admin role. Upgrade inside the extension.

Overview
Tasks
CMDB
API
Metrics
Monitor
Internals
Instance:sourdoughdev·Version:Yokohama
Instance StateONLINE
System StatusFully Operational
Session Timeout90 minutes
Logged-In Sessions2 (20 active)
Build Nameyokohama-12-18-2024_p1
IP Address10.159.128.43
Instance HealthHealth Score: 90%
🔥 5dSourdough (Chrome Plugin)Dark Mode

Step by step

1

Create the business rule

Navigate to System Definition > Business Rules and click New. Set the Table to your triggering table and Name to something descriptive like 'Update Parent Project Status'. Set When to 'after' since you're updating a different record, not the current one. Check Insert and Update unless you only need one trigger type.

TIP

Use 'after' rules for related record updates — 'before' rules run before the database commit and can cause timing issues.

2

Add the condition

In the Condition field, specify exactly when this rule should run. For example, if updating a parent when a status changes, use current.state.changesTo('7'). If you need to check multiple conditions, use current.state.changes() && (current.state == '3' || current.state == '7'). Don't leave this blank — unconditional rules kill performance.

TIP

Use changesTo() and changesFrom() instead of changes() when you care about specific values — it prevents unnecessary rule executions.

3

Query the related record

In the Script field, start by getting the related record with GlideRecord. Use var parentGR = new GlideRecord('parent_table'); parentGR.get(current.parent); if (!parentGR.isValidRecord()) return; This gets the parent record referenced by the current record's parent field and exits early if it doesn't exist.

TIP

Always check isValidRecord() after get() — reference fields can point to deleted records or have invalid sys_ids.

4

Update the target field

Set the field value on your queried record: parentGR.status = 'Complete'; or parentGR.setValue('u_custom_field', 'New Value'). Use setValue() for reference fields, choice fields, or any field where you need type conversion. Use direct assignment for simple text or number fields.

TIP

Use setValue() with the internal value for choice fields — setValue('state', '3') not setValue('state', 'Closed').

5

Configure silent update

Before calling update(), add parentGR.setWorkflow(false); and parentGR.autoSysFields(false); These prevent the update from triggering other business rules, notifications, and workflows. Then call parentGR.update(); to save the changes.

TIP

Silent updates are critical — without them, your rule can trigger cascading business rules and create performance problems or infinite loops.

6

Add loop prevention

If your rule updates records on the same table it triggers from, add a condition to prevent infinite loops. Use if (current.isNewRecord() || current.u_processing_flag.changes()) return; at the start, then set current.u_processing_flag = true; before your related record logic. This prevents the rule from triggering itself.

TIP

Create a boolean field like 'u_processing_flag' specifically for loop prevention — don't reuse business fields for technical control.

7

Test with multiple scenarios

Test your rule by updating records that should trigger it and verifying the related record updates correctly. Test edge cases: records with no parent, parents that don't exist, and bulk updates. Check that silent updates aren't triggering unexpected side effects and that your conditions prevent unnecessary executions.

Best practices

  • Always use setWorkflow(false) and autoSysFields(false) when updating related records — cascading business rules are a major cause of performance problems.

  • Never update records on the same table your business rule triggers from without explicit loop prevention — infinite loops will crash your system.

  • Use specific change detection like current.state.changesTo('7') instead of current.state.changes() — it dramatically reduces unnecessary rule executions.

  • Check isValidRecord() after every GlideRecord.get() call — reference fields often point to deleted or invalid records.

  • Put your most restrictive conditions first in compound conditions — if (!current.parent || !current.state.changes()) return; fails fast and saves processing time.

Test Your Knowledge

Quick 3-question quiz — see how your ServiceNow skills stack up.

Question 1 of 3Performance

A list view on a table with millions of records is slow. Best fix?

Select an answer to continue