GlideRecord
Quick answer
GlideRecord is the server-side Java-backed API for reading and writing table data. It is the single most-used class in ServiceNow, and almost every business rule, script include, scheduled job and background script leans on it.
Key takeaways
- The four operations
- Building query conditions
- getValue, getDisplayValue, and the field trap
- Dot-walking through references
- Writing: insert, update, and the return value
GlideRecord is the server-side Java-backed API for reading and writing table data. It is the single most-used class in ServiceNow, and almost every business rule, script include, scheduled job and background script leans on it. Understanding not just how to query but how GlideRecord behaves, lazy loading, journalled writes, dot-walking, and its performance envelope, separates a scripter who copies snippets from one who can be trusted with production data.
The four operations
Every GlideRecord script is some combination of query, read, write, delete. The lifecycle is always: instantiate against a table, narrow with query conditions, execute, then iterate.
Two things to internalise. First, nothing touches the database until query(), building conditions is cheap, executing is not. Second, GlideRecord is a cursor: next() advances one row at a time; the whole result set is not loaded into memory at once.
Building query conditions
The condition builder is richer than addQuery(field, value). The three-argument form takes an operator, and several helpers cover ORs, ranges and null checks.
addEncodedQuery(). It is faster and less error-prone than hand-assembling complex AND/OR logic, and it guarantees the operators are valid.Common operators: =, !=, >, <, >=, <=, IN, NOT IN, STARTSWITH, ENDSWITH, CONTAINS, DOES NOT CONTAIN, LIKE.
getValue, getDisplayValue, and the field trap
This is the number-one source of GlideRecord bugs. A field accessed directly (gr.assigned_to) returns a GlideElement object, not a string, it only looks like a string when concatenated. On a reference field that surprises people badly:
Rule: compare and store on getValue() (the sys_id); show the user getDisplayValue(). Always call getValue() explicitly rather than relying on implicit coercion, it makes intent obvious and avoids the object-vs-string trap in conditionals.
Dot-walking through references
Because a reference field points at another record, you can walk across the relationship in one expression, no second query needed. GlideRecord resolves it for you:
Writing: insert, update, and the return value
Prefer setValue()/getValue() over direct assignment in scripts you care about, they are unambiguous about strings vs objects. insert() returns the new record's sys_id (or null if a data policy or ACL blocked it), and update() returns the sys_id of the updated row.
Deleting, and why deleteMultiple exists
get() is the shortcut for fetching exactly one record, pass a sys_id, or a field/value pair. It returns a boolean so you can guard the block.
Counting and aggregating without pulling rows
When you only need a count or a sum, never query all rows and count in a loop, that drags every record into memory. Use GlideAggregate, which pushes the maths to the database:
Handling dates & times
Date fields are best manipulated with GlideDateTime rather than string arithmetic, so time zones and DST are handled correctly:
Key methods at a glance
Performance & safety
- Filter at the database, not in script. Add every condition you can to the query; don't
next()through everything andifinside the loop. - Use
setLimit()when you only need the first N rows, it stops the DB fetching more. - Avoid
getRowCount()on large tables, it can force a full scan; use GlideAggregate COUNT instead. - Mind the query business rule. A GlideRecord run as a normal user is filtered by ACLs;
setWorkflow(false)andautoSysFields(false)control whether business rules and audit fields fire on writes. - GlideRecordSecure enforces ACLs in server scripts where you explicitly want row-level security applied.
query() and a update() in the loop, run against a million-row table with setWorkflow(true). Every update fires business rules, which fire more queries. Always test with setLimit(1) and gs.info() before you let a bulk write run for real.Common mistakes
- Forgetting
query(), the loop silently never runs. - Using a field in string context and getting a sys_id where you expected a name.
- Looping
deleteRecord()or counting in script instead ofdeleteMultiple()/ GlideAggregate. - Unbounded bulk updates that fire business rules a million times.
- Assuming a server script sees all rows, as a non-admin user, ACLs filter the result.
Want to learn this properly?
Our live, instructor-led ServiceNow Training covers this hands-on, with real projects and a certification path.
Check your understanding
Which method actually executes the query?
- A. addQuery()
- B. query()
- C. next()
Show answer
B. query()
addQuery only builds the filter; query() runs it.
GlideRecord is primarily which kind of API?
- A. Client-side
- B. Server-side
- C. CSS
Show answer
B. Server-side
It is a server-side API.
How do you safely read a field's value?
- A. gr.field
- B. gr.getValue('field')
- C. gr.print()
Show answer
B. gr.getValue('field')
getValue returns a string reliably.