Reference fields point to records, but client scripts need to access those related records' data. This guide shows you the reliable way to get sys_ids and field values from referenced records in client scripts.
Why reference field access breaks in client scripts
Most developers discover reference field access the hard way — they write a client script that dot-walks a reference (like g_form.getValue('assignment_group.name')), it works sporadically during testing, then breaks in production when the referenced record data isn't pre-loaded. Client scripts run in the user's browser with limited data, unlike server-side scripts that can query anything. The platform only sends referenced record data to the browser when it thinks you'll need it, which is unpredictable. Developers who maintain forms with complex reference logic spend hours debugging intermittent failures caused by this timing issue.
How reference field access actually works
ServiceNow gives you two methods: g_form.getValue() returns the sys_id stored in the reference field (always reliable), and g_form.getReference() fetches the full referenced record via callback (reliable but asynchronous). Most developers start with getValue() for sys_ids and think they can dot-walk for other fields — that's the trap. The right approach is getValue() when you only need the sys_id, and getReference() with a callback function when you need any other field from the referenced record. The callback pattern feels awkward at first, but it's the only way to guarantee the data is available when your code runs.
Building robust reference field logic
Once you understand the async pattern, you can build client scripts that reliably access reference data regardless of what's pre-loaded. Advanced techniques include chaining multiple getReference() calls when you need data from multiple reference fields, caching reference data in global variables to avoid repeated lookups, and combining GlideAjax calls for complex queries that getReference() can't handle. Production-quality reference scripts also handle error cases — what happens when the referenced record is deleted or the user doesn't have read access to it.
Before you start
- •Client script record already created
- •Form with reference fields to test against
Sourdough: ServiceNow Monitoring and Analytics
A Chrome extension for ServiceNow Admins and Developers with essential tools, analytics, graphs and monitoring features.
Free to install. Pro $5/month after a 14-day no-card trial.
Pro requires the ServiceNow admin role. Upgrade inside the extension.
Step by step
Get the reference field sys_id
Use g_form.getValue('field_name') to retrieve the sys_id of the referenced record. This works immediately and synchronously — no callback needed. The sys_id is what's actually stored in the reference field, so this method never fails due to timing issues.
Store the sys_id in a variable first — you'll often need it for comparisons or GlideAjax calls.
Set up the getReference callback structure
Write g_form.getReference('field_name', callback_function) where callback_function is a function that receives the referenced record as a parameter. Define your callback function to accept one parameter — this will be the GlideRecord object containing the referenced record's data. Put all your reference field logic inside this callback function, not after the getReference call.
Name your callback parameter something descriptive like 'referencedUser' or 'assignmentGroup' instead of generic names.
Access fields from the referenced record
Inside your callback function, use standard GlideRecord dot-notation to access fields from the referenced record. For example: referencedRecord.field_name or referencedRecord.getValue('field_name'). The callback ensures this data is loaded before your code tries to access it. Handle the case where the reference might be empty by checking if the callback parameter exists before accessing its fields.
Handle the display value separately
Use g_form.getDisplayValue('field_name') to get the display value (what the user sees) of the reference field. This is synchronous like getValue() and returns the referenced record's display field immediately. Don't use getReference() just to get the display value — getDisplayValue() is faster and doesn't require a callback.
The display value is usually the 'name' field of the referenced table, but some tables use different display fields.
Test with empty references
Clear the reference field and test your script to ensure it handles null/empty references gracefully. Your callback function should check if the referenced record parameter exists before accessing its properties. Add conditional logic like 'if (referencedRecord)' before any field access to prevent JavaScript errors when the reference is empty.
Avoid dot-walking in the main script
Never use g_form.getValue('reference_field.some_field') or similar dot-walking syntax outside of server-side scripts. This appears to work when ServiceNow pre-loads the reference data, but fails unpredictably when it doesn't. Always use the getReference() callback pattern for accessing referenced record fields, even if dot-walking seems to work in your test environment.
Best practices
Never dot-walk reference fields in client scripts — g_form.getValue('assigned_to.department') will fail intermittently when the referenced data isn't pre-loaded.
Use g_form.getValue() for sys_ids and g_form.getDisplayValue() for display values — both are synchronous and reliable without callbacks.
Put all reference-dependent logic inside the getReference() callback function — code after the getReference() call runs before the callback completes.
Check if the referenced record exists in your callback with 'if (referencedRecord)' before accessing fields to handle empty reference fields gracefully.
Cache reference data in global variables if you need it in multiple functions — calling getReference() repeatedly for the same field wastes performance.
Test Your Knowledge
Quick 3-question quiz — see how your ServiceNow skills stack up.
A list view on a table with millions of records is slow. Best fix?
Select an answer to continue