Skip to main content
Version: Latest (4.7.0)

Assignment Rules

Guide for creating ServiceNow Assignment Rules using the Fluent API. Assignment rules automatically populate assignment_group or assigned_to fields on task or task-inherited tables when a record is created or updated.

When to Use

Any custom table whose parent or ancestor is task (directly or through any of the tables below) qualifies for assignment rules. If the table does NOT extend task, use a Business Rule instead.

OOB Task-Extended Tables

The following are examples of out-of-box tables that extend task. Any custom table that extends task or any of these tables can use assignment rules:

OOB tableLabel
taskTask (base)
incidentIncident
change_requestChange Request
change_taskChange Task
problemProblem
problem_taskProblem Task
sc_requestRequest
sc_req_itemRequested Item
sc_taskCatalog Task
sn_si_incidentSecurity Incident
hr_caseHR Case
hr_taskHR Task
csm_orderConsumer Order

Example: If you create a custom table u_security_task that extends sn_si_incident, it can use assignment rules because sn_si_incident extends task.

Use assignment rules when:

  • Automatically assigning tasks, incidents, changes, or problems to users or groups
  • Routing records to teams based on specific conditions (category, priority, location)
  • Implementing workload distribution logic (round-robin, load balancing)
  • Assigning records based on field values (e.g., "assign hardware incidents to hardware team")
  • Setting up dynamic assignment using scripts
  • User wants a team to already appear / be pre-populated in the assignment group when a form opens
  • User wants to avoid manual team selection
  • Custom table extends or inherits from any task-based table and needs automatic user or group assignment on form open

Assignment rules vs Business rules

Use Assignment Rules when:

  • Primary goal is to assign records to users or groups when creating or updating a record
  • Working with task or task-extended tables (incident, change, problem, etc.)
  • Assignment logic is condition-based and relatively straightforward
  • You want to use the platform's built-in assignment engine

Use Business Rules when:

  • You need assignment to happen on insert, update, or other database operations (not record open) or tables not extended from tasks
  • You need complex logic beyond assignment (field updates, validations, integrations)
  • You need precise control over timing (before/after/async/display)
  • You need to perform multiple operations beyond assignment
  • You need to work with tables that don't inherit from task tables
  • You need assignment logic to run in the background without user interaction

Key Concepts

Assignment rules run when you open a record and automatically set assigned_to or assignment_group fields.

Important limitations:

  • Assignment rules are only applicable to task or task-extended tables (incident, change_request, problem, sc_req_item, etc.)

Static assignment vs Script-based assignment

Static Assignment (Recommended for Simple Cases):

  • Set group field to a specific group sys_id
  • Set user field to a specific user sys_id
  • No script needed
  • Fast and simple
  • Example: "All hardware incidents go to Hardware group"

Script-Based Assignment (For Complex Logic):

  • Use script field to write JavaScript assignment logic
  • Access current record via current variable
  • Use setDisplayValue() for setting groups/users by name
  • Example: Round-robin assignment, load balancing, conditional logic

Static vs Script-Based:

  • Static: Set group or user field to a sys_id (simple, fast)
  • Script-Based: Use script field for conditional logic, round-robin, etc.

Instructions

Pre-flight: Validate group/user existence (MANDATORY)

Before writing any code, query the instance to confirm the target group or user exists.

  • Skip only if: the user has explicitly provided the sys_id — use it directly.
  • If the query succeeds and returns a match: Use the sys_id from the result in the group or user field for static assignment.
  • If the query returns no match: Query again with a partial/case-insensitive name to find similar records. If still not found, STOP and ask the user: (a) provide the sys_id directly if they know it, (b) create the group/user, (c) use a different existing group/user, or (d) proceed with a script-based setDisplayValue() approach (with the caveat that it will only work once the group/user is created).
  • If the query cannot be executed (MCP unavailable, auth failed, instance unreachable): STOP and inform the user before proceeding.

Follow these steps to implement assignment rules:

  1. Verify table eligibility (CRITICAL): Confirm the table extends task (incident, change_request, problem, sc_req_item, change_task, sc_task, or custom task-inherited table). Assignment rules do NOT work on non-task tables. Always verify the correct table name with the user.

  2. Define conditions: Specify when the rule should fire when a record is opened (category, priority, status, custom fields). Use the condition field with ServiceNow's encoded query syntax. Assignment rules evaluate conditions before executing scripts.

  3. Set match conditions: Set match_conditions to 'ALL' (default) to require all conditions to match, or 'ANY' to match if any condition is true.

  4. Determine assignment target: Decide on group vs user assignment or both. Groups are preferred for scalability and flexibility. If the group or user name is not explicitly provided, query the sys_user_group table (for groups) or sys_user table (for users) to get the correct name or label before proceeding.

  5. Write script if needed: For simple assignments (static group/user), set the group or user field directly using the sys_id obtained in the Pre-flight step. For moderately complex logic (round-robin, load balancing, conditional routing by category), use the script field with server-side JavaScript. If the logic is very complex (requires external API calls, multiple GlideRecord queries, aggregated data, or exceeds 8000 characters), use a business rule instead — assignment rules are designed for straightforward routing at record open time.

  6. Single rule for multiple use cases (CRITICAL): When handling multiple assignment scenarios for the same table (e.g., hardware incidents → Hardware Team, software incidents → Software Team, network incidents → Network Team), create a single script-based assignment rule with conditional logic (if/else statements) rather than multiple separate assignment rules. This improves maintainability and avoids order-dependent conflicts.

  7. Set execution order: If multiple rules exist, set appropriate order values. Lower numbers run first (e.g., order 10 runs before order 50, which runs before order 100). Default is 100. Use this to implement tiered assignment strategies:

    • High priority rules (order 1-30): VIP callers, critical incidents, emergency changes
    • Medium priority rules (order 40-70): Specialized routing based on specific conditions
    • Default/catch-all rules (order 80-100): General assignment for unassigned records
  8. Configure metadata: Set active: true to enable the rule. Use clear, descriptive names that explain what the rule does (e.g., "Assign Hardware Incidents to Hardware Team"). Use Now.ID["identifier"] where the identifier is in kebab-case (lowercase with hyphens) and descriptively matches the rule's purpose. Examples: Now.ID["hardware-incident-assignment"], Now.ID["vip-caller-assignment"].

API Reference

Assignment rules use the generic Record() API with table: "sysrule_assignment". There is no dedicated AssignmentRule() Fluent API.

Table Schema

FieldTypeRequiredDescription
nameStringYesDescriptive name for the rule (max 40 characters).
tableTableNameYesTarget table (must extend task). Default: 'incident'.
activeBooleanNoWhether the rule is active. Default: true.
conditionStringNoEncoded query defining when the rule fires (max 1000 characters). Must end with ^EQ.
match_conditionsStringNoHow multiple conditions are evaluated: 'ALL' (all must match) or 'ANY' (any matches). Default: 'ALL'.
groupReferenceNosys_id of the assignment group (sys_user_group). Prefer over user for scalability.
userReferenceNosys_id of the assigned user (sys_user). Use for individual assignment.
scriptStringNoServer-side JavaScript (max 8000 characters). current is the opened record. Overrides group/user.
orderIntegerNoExecution order. Lower numbers run first. Default: 100.
descriptionStringNoDescription of the rule's purpose (max 4000 characters).

Condition Syntax

Encoded query syntax (must end with ^EQ): = (equals), != (not equal), ^ (AND), ^OR (OR), IN (list), ISEMPTY, ISNOTEMPTY

category=hardware^EQ // Single condition
category=hardware^priority=1^EQ // AND condition
stateIN1,2^EQ // OR list

Script Patterns

Use Now.include("path/to/file.js") for external scripts or inline with backticks. Access record via current variable.

// Simple assignment
current.assignment_group.setDisplayValue("Hardware Team");

// Conditional
if (current.priority == "1") {
current.assignment_group.setDisplayValue("Critical Response Team");
} else {
current.assignment_group.setDisplayValue("Standard Support");
}

Examples

Static Group Assignment

import '@servicenow/sdk/global'
import { Record } from "@servicenow/sdk/core";

export const hardwareIncidentAssignment = Record({
$id: Now.ID["hardware-incident-assignment"],
table: "sysrule_assignment",
data: {
name: "Assign Hardware Incidents to Hardware Team",
table: "incident",
active: true,
condition: "category=hardware^EQ",
group: "<sys_id_of_hardware_group>",
order: 100
}
});

Script-Based with Now.include

Fluent Definition:

import '@servicenow/sdk/global'
import { Record } from "@servicenow/sdk/core";

export const categoryBasedAssignment = Record({
$id: Now.ID["category-based-assignment"],
table: "sysrule_assignment",
data: {
name: "Assign by Category",
table: "incident",
active: true,
order: 100,
script: Now.include("../../server/assignment-rules/category-based.js")
}
});

Script File:

if (current.category == "Hardware")
current.assignment_group.setDisplayValue("Hardware");
else if (current.category == "Software")
current.assignment_group.setDisplayValue("Software");
else
current.assignment_group.setDisplayValue("Service Desk");

Execution Order Priority

// High priority (order 10) - runs first
import '@servicenow/sdk/global'
import { Record } from "@servicenow/sdk/core";

export const vipAssignment = Record({
$id: Now.ID["vip-assignment"],
table: "sysrule_assignment",
data: {
name: "VIP Caller Assignment",
table: "incident",
condition: "caller_id.vip=true^EQ",
group: "<vip_support_group_sys_id>",
order: 10
}
});

// Default (order 100) - runs last
export const defaultAssignment = Record({
$id: Now.ID["default-assignment"],
table: "sysrule_assignment",
data: {
name: "Default Assignment",
table: "incident",
condition: "assignment_group=^EQ",
group: "<service_desk_sys_id>",
order: 100
}
});

Round-Robin Assignment

import '@servicenow/sdk/global'
import { Record } from "@servicenow/sdk/core";

export const roundRobinAssignment = Record({
$id: Now.ID["round-robin-assignment"],
table: "sysrule_assignment",
data: {
name: "Round-Robin Assignment",
table: "incident",
order: 100,
script: Now.include("../../server/assignment-rules/round-robin.js")
}
});

Script:

var gr = new GlideRecord("sys_user_grmember");
gr.addQuery("group.name", "Service Desk");
gr.addQuery("user.active", true);
gr.query();

var users = [];
while (gr.next()) users.push(gr.user.sys_id.toString());

if (users.length > 0) {
var incidentNum = parseInt(current.number.toString().replace(/[^0-9]/g, ""));
current.assigned_to = users[incidentNum % users.length];
current.assignment_group.setDisplayValue("Service Desk");
}

Avoidance

  • Never use on non-task tables — Use business rules instead
  • Never expect to run on insert/update — Runs on record open only
  • Never create multiple rules for same table — Use single rule with if/else logic
  • When using script, avoid setting group/userscript silently overrides static assignments; setting both is confusing and the static values are ignored
  • Never skip the instance query (step 5) — Always query sys_user_group or sys_user on the instance before writing the rule. Do NOT use setDisplayValue() or ask the user whether to create/use setDisplay until after a query has been attempted and returned no match. A queried sys_id used in the group/user field is the preferred outcome — this is NOT hardcoding. Exception: If the user has explicitly provided the sys_id, skip the query and use it directly.
  • Never silently fall back to setDisplayValue()setDisplayValue() is only acceptable when explicitly chosen by the user after being informed the group/user was not found on the instance (see step 5 options). It must never be used as a default or convenience shortcut.
  • Avoid complex logic — If script exceeds 8000 chars, needs external APIs, or multiple GlideRecord queries, use business rule instead

See business-rule-guide, client-script-guide, table-guide topics