ServiceNow Script Include Explained
What a Script Include Is
A Script Include is a reusable block of server-side JavaScript code that you call from anywhere in ServiceNow: from workflow actions, from custom buttons, from scheduled jobs, or from other scripts. Instead of duplicating the same logic multiple times, you write it once in a Script Include and call it whenever you need it. Script Includes reduce code duplication, make your code easier to maintain, and ensure consistent behavior across your platform.
Script Includes run on the ServiceNow server, not in the browser. They have full access to the ServiceNow database tables and APIs. They can read and write configuration records, query multiple tables, make external API calls, and perform calculations. The JavaScript syntax is similar to browser JavaScript but with access to server-only ServiceNow APIs.
Where Script Includes Live in the Platform
You create Script Includes in the System Definition application or through development tools. Each Script Include has a name, optional description, and the JavaScript code itself. You can organize Script Includes by purpose: utility functions, API wrappers, business logic. Many teams create Script Includes for integration patterns they use repeatedly.
Script Includes can be marked as callable from client-side scripts (the browser), or restricted to server-side only. Most are server-only because they access sensitive data or perform database operations. You reference a Script Include by its class name and call its methods just like you would call a JavaScript class method.
A Worked Example
Imagine you need to find all incidents related to a particular configuration item. You write this logic once in a Script Include called IncidentQueries. You define a method that takes a configuration item ID and returns a GlideRecord object containing all related incidents. Now, whenever a workflow needs to find incidents related to a CI, you call IncidentQueries.getIncidentsForCI(ciID) instead of writing the query each time.
Later, your organization decides to exclude certain incident types from these queries. Instead of updating the query in five different places, you update the Script Include once. All code that uses it automatically gets the new behavior. This is the maintenance advantage: change the logic in one place and fix the issue everywhere.
Another common pattern: a Script Include wraps an external API. The Include handles authentication, request formatting, error handling, and response parsing. Code that calls the API does not need to understand all those details; it just calls the Include’s method. If the external API changes, you update the wrapper once.
Common Patterns and Practices
Utility Script Includes provide general-purpose functions: string manipulation, date calculations, validation logic. These are used everywhere and save time. Integration Script Includes wrap external APIs and are used by multiple workflows. Business logic Includes encode your organization’s specific rules: how to calculate SLA targets, when to escalate, how to assign work to teams. These Includes make your workflows easier to read and modify.
Script Includes can also define object-like structures that make your code more readable. Instead of passing five separate parameters to a method, you pass an object containing those fields. This makes calling code clearer and makes the Script Include easier to extend when you need to add new capabilities.
Performance and Limitations
Script Includes execute on the server and return results to the calling code. Long-running Script Includes can slow down workflows. Querying thousands of records or making multiple external API calls in a Script Include may time out depending on your system’s configuration. Writing efficient queries using GlideRecord syntax and caching results when possible keeps Script Includes responsive.
Script Includes that modify database records should be used carefully in workflow actions. If a Script Include modifies incident records during a workflow, make sure you understand what fields change and whether that behavior applies to all uses of the workflow or only some.
Deciding whether logic belongs in a Script Include at all
Once a team has a few Script Includes, there is a pull to put everything in one, because a shared library feels tidy. That pull can produce libraries that nobody can change safely, since every caller depends on every method. The first design decision is therefore not how to write the include but whether the logic should be one. Logic that is called from several places and has a stable meaning belongs in an include. Logic that is tied to one table’s behavior on save usually belongs in a business rule, and logic that a process owner needs to see and adjust belongs in a flow.
The question to ask is who will need to read and change the code, and when. A developer who maintains the logic for a shared calculation is the right owner for an include. A process owner who wants to alter an approval threshold is better served by a flow or a documented configuration record that the include reads.
Choosing the container for each piece of logic
The following comparison is a practical way to decide. It assumes the logic is server-side, since client-side needs follow a different path.
| Need | Script Include | Business rule | Flow action or subflow |
|---|---|---|---|
| Same calculation used in several places | Strong fit, one definition with one owner | Weak, each rule would hold its own copy | Possible, but hard to reuse from script |
| Reaction to a record being saved or deleted | Called from a rule, rarely the trigger itself | Strong fit, runs on the table event | Possible through a trigger, but more indirect |
| Step that a process owner must see and edit | Poor fit, hidden in code | Poor fit, hidden in code | Strong fit, visible in the flow diagram |
| Wrapper around an external service | Strong fit, holds authentication and parsing | Weak, too much logic in a trigger | Good, when the flow is the caller |
| Client-side lookup from a form | Possible, only if marked client callable and kept read-only | Not applicable | Not applicable |
Scope, access and client callable settings
Three settings decide who can reach an include, and they are easy to set carelessly. The accessibility setting controls whether code in other application scopes may call the include, and a team that defaults it to the widest option has, in effect, published an internal API to the whole instance. Setting it to the narrowest option that still works for the current callers keeps the surface small, and widening it later is a deliberate step that can be reviewed.
The client callable option lets browser-side code call the include through an asynchronous request. It is needed for patterns that populate a form field from a lookup, but it exposes every public method to any logged-in user who can reach the form. Methods that return sensitive values, or that write records, should not be exposed that way. A common practice is to keep one client-callable include per purpose, with only read methods, and to keep the write logic in server-only includes.
Every method should also be checked against the access rules of the caller. A server-side include runs with the permissions of the code that called it, so a GlideRecord query inside the include can return rows the requesting user would not otherwise see if the include is called from a privileged context. The reviewer should ask, for each method, whose access it is using.
A build sequence that keeps the include reviewable
Script Includes change behavior for every caller at once, so the way they are built and promoted matters as much as the code inside them. The sequence below keeps the change visible and recoverable.
- Name the purpose of the include in one sentence, and check that no existing include already serves that purpose.
- Choose the narrowest accessibility setting that the known callers require, and mark client callable only if a form genuinely needs it.
- Write each public method with a single documented input and a single documented output, so a caller can be checked without reading the whole include.
- Test the methods from a caller with the same role the production caller will use, not from an administrator’s session.
- Before promoting, list every rule, flow and widget that references the include by name, and confirm each still works after the change.
- Record the change in the update set description with the callers reviewed, so the next person can see the blast radius.
The last step is the one that makes later maintenance cheap. Teams that skip it often discover, months later, that an include they edited was quietly used by a flow nobody remembered.
What tends to break once includes are in use
- A method that was written for one caller gains a second caller with different assumptions about empty results, and a failure appears only in the second flow.
- An include is renamed or deleted in a clean-up, and a caller that references it by name fails silently or only when a rare branch runs.
- A client-callable include gains a write method during a quick fix, which then becomes reachable from any form that can call it.
- Logic that should live in a rule or a subflow grows inside the include, so an administrator who changes a process no longer knows where to look.
- The include caches a value that changes during the day, and the cache keeps serving the old value until the next restart or cache reset.
Many of these are visible in code review if the reviewer asks two questions: who calls this method, and what happens when it returns nothing. The scripted REST API design contracts guidance uses the same thinking when a method is exposed outside the platform.
Questions about Script Include design
How many Script Includes is too many?
There is no universal count. The signal is that a developer cannot find the include they need within a short search, or that two includes do almost the same thing. Consolidating duplicates is usually worth more than splitting a large include for its own sake.
Can an include call another include?
Yes, and that is normal for layered logic. Keep the dependency direction clear, so a utility include does not depend on a business include, and watch for circular references that only fail under a particular call order.
Should an include be tested automatically?
Yes, where the team has an automated test practice. A test that calls each public method with an empty, typical and unexpected input catches many of the regressions that the failure list above describes.
When should an include be retired?
Retire it once the reference search shows no callers over a full business cycle, not when the developer believes the callers have moved. Keep a note of the removal in the change record, so a later failure can be traced back to it.
What a Script Include looks like: three shapes and one naming rule
A Script Include is a named server-side script, and it can take one of three shapes: a class with methods, a single function, or an extension of an existing class. The rule that catches most beginners is that the include’s name must match the class or function name inside it. If the two differ, the platform cannot find the code and calls fail with an undefined error.
The class shape is the one most teams use, because it groups related methods under one name:
var IncidentQueries = Class.create();
IncidentQueries.prototype = {
initialize: function() {},
getIncidentsForCI: function(ciId) {
var gr = new GlideRecord('incident');
gr.addQuery('cmdb_ci', ciId);
gr.query();
return gr;
},
type: 'IncidentQueries'
};
Server-side code then calls it with new IncidentQueries().getIncidentsForCI(id). The function shape holds one function whose name equals the include name, which suits a single small utility. The extension shape builds on a class that already exists, and it is the shape used when an include must be reachable from the browser.
For browser calls, the include extends the platform’s Ajax processor class and the form script calls it through a GlideAjax request. Only methods that are meant to be public should be reachable that way, and a client-callable include should stay read-only unless a write is truly the purpose.
| Shape | Use it when |
|---|---|
| Class with methods | Several related methods share one owner and one name |
| Single function | One small utility with no state |
| Extension of an existing class | Browser-side lookups through GlideAjax, or changing shared behaviour without copying it |
Move includes between instances through an update set so the change is tracked, and keep them inside the scope that owns the feature. The update sets and release management guide covers that route, the scoped application architecture page explains where an include belongs, and the Flow Designer action guide shows when a flow step is the better container.
Frequently asked questions
Should I put all my code in Script Includes or create them only for truly reusable logic?
Create Script Includes for logic you use in two or more places, or for complex calculations that are hard to read inline. Logic used in only one place may be simpler to maintain inline in the workflow. Strike a balance between avoiding excessive Script Includes and avoiding code duplication.
Can Script Includes call other Script Includes?
Yes. Script Includes can call other Script Includes, creating a hierarchy of reusable components. This is useful for building abstractions: a high-level Script Include calls lower-level Includes to compose more complex behavior. Just be aware of performance: calling many layers of Script Includes adds latency.
What is the difference between a Script Include and a Business Rule?
A Business Rule runs automatically when a record is created, updated, or deleted. A Script Include is called manually whenever code needs it. Business Rules are for automatic reactions to record changes. Script Includes are for reusable logic called explicitly. You can call a Script Include from a Business Rule, but not vice versa.
Related guides
Related Oblytech services
Where this topic turns into delivery work, these are the Oblytech services that cover it.
Planning, running or fixing a ServiceNow programme? Tell us where you are and we will suggest a sensible next step.
Contact us