Skip to content

Before Query Business Rules vs Security Data Filters: When and How to Migrate

Yancoubou Gassama

Yancoubou Gassama

ServiceNow Senior Consultant

Oct 26, 2026 7 min
A legacy script editor migrating to a declarative security filter with conditions and a shield

On many ServiceNow instances, row-level visibility still relies on Before Query business rules written years ago: a script that appends a condition to every query on a table so that users only see the records they are supposed to see. They work, which is exactly why nobody dares to touch them.

Since the Xanadu and Yokohama releases, ServiceNow offers a mechanism built for that exact job: Security Data Filters. ServiceNow presents them as an alternative to Before Query business rules that applies safeguards directly to database queries.

Moving from one to the other is not a find and replace, though. Some rules gain a lot from the migration, some cannot move at all, and a careless migration can expose data you thought was protected. This article explains where the gains are, where the traps are, and how to migrate safely.

Why Before Query rules became debt

A Before Query business rule runs before the database query and adds conditions to it. It was never designed as a security feature: it is a general-purpose script hook that teams repurposed for data segregation. The ServiceNow documentation asks to use them only when necessary, warns that too many of them affect instance performance, and recommends limiting OR clauses and searches on non-indexed fields.

In practice, three problems come back on almost every instance:

  • They also filter server-side GlideRecord queries. A rule written for list views can silently change what scheduled jobs, flows or integrations see, unless every rule carries the right guard.

  • They are code. Each rule embeds its own logic, often calls Script Includes, and must be reviewed, tested and maintained like any other script.

  • They are hard to diagnose. ACL debugging does not report them, so a user who is missing records can send a team looking in the wrong place.

A typical rule looks like this:

(function executeRule(current, previous) {
    // Only filter interactive sessions, never background scripts
    if (!gs.getSession().isInteractive() || gs.hasRole('admin'))
        return;
    // Agents only see incidents assigned to one of their groups
    current.addQuery('assignment_group', gs.getUser().getMyGroups());
})(current, previous);

The isInteractive guard is the only thing keeping this rule out of background processing. Forget it once, and your automation is filtered too.

What Security Data Filters change

A Security Data Filter is a declarative record, managed under System Security by people holding the security_admin role. It combines a table, a filter condition built with the condition builder, and a security attribute that decides who the filter applies to, in an If or Unless mode. The rule above becomes a filter on Incident with the condition "Assignment group is one of my groups", applied unless the user holds the admin role.

When a query hits the table, the platform appends the condition to the SQL query itself, so restricted rows never leave the database. Several filters on the same table are combined with AND. Like a Before Query rule, a filter also removes the "rows removed by security constraints" message from lists, because unauthorized rows are never fetched.

The key behavioral change is the scope. Filters apply by default to GlideRecordSecure, GlideRecordSandbox and GlideAggregateSandbox queries. Server-side scripts can turn them on or off explicitly with enableSecurityFeature and disableSecurityFeature, but a plain GlideRecord is not filtered unless you ask for it.

The concrete benefits of migrating

  • A feature designed for security. A ServiceNow employee explains that Security Data Filters are an official part of the platform security architecture and go through much more quality assurance than Before Query rules, which were never built for that purpose.

  • Security stays where it belongs. Because plain GlideRecord is not filtered by default, a filter no longer leaks into scheduled jobs, flows and integrations. No more isInteractive guards to remember.

  • Declarative, auditable rules. A condition and a security attribute can be read by an auditor or an architect without opening a script editor.

  • Reusable security attributes. The same attribute can drive several filters and ACLs, so the definition of "who is exempt" lives in one place.

  • Measurable performance. The performance analysis tool runs a sample query with and without the filter and rates the impact on median execution time as Low, Medium or Critical, before anything reaches production.

Rules you should not migrate as is

Not every Before Query rule is a good candidate. Four cases deserve a second look before any rewrite.

  • OR logic across rules. Several filters on one table combine with AND, while Before Query rules can build OR conditions, including the ^NQ operator. A set of rules that each open access to a different population cannot be translated one filter per rule: it has to be redesigned as a single condition.

  • Heavily scripted logic. When access depends on computed values, such as a management chain walked in a Script Include, the condition builder may not express it. Security attributes can carry a script, but it evaluates the user context, not the record.

  • Domain separation workarounds. If the rule compensates for segregation in a service provider instance, look at the Domain Separation plugin first. ServiceNow states that Before Query rules are not a substitute for it.

  • Rules that are not about security. Filtering a list for convenience is a visibility concern. The documentation advises caution when using data filters as visibility controls.

Pitfalls after the migration

The migration changes behavior in ways that tests focused on list views will not catch.

  • Custom code that relied on the old rule. Script Includes behind portal widgets, UI pages or scripted REST APIs often query with plain GlideRecord and silently counted on the Before Query rule. After the switch they return unfiltered data. ServiceNow recommends enabling data filters explicitly for user-facing queries that do not use GlideRecordSecure.

  • Parent tables. A filter on a child table does not apply when the data is queried through the parent. A filter on Incident is bypassed by opening a Task list filtered on incidents. Add a filter on both tables.

  • Indirect queries. Community guidance written by a ServiceNow employee describes how a list report on Affected CIs can display fields of protected tasks when the report sets no condition on the Task table itself.

  • Performance. Every query on the table carries the extra condition. Unindexed columns, many conditions and operators such as contains are the usual causes of slow lists.

This is why the same need-to-know guidance recommends combining Security Data Filters with Deny-Unless ACLs: each mechanism covers the blind spots of the other.

A five-step migration method

  1. Inventory. List active business rules with the Query action checked (encoded query action_query=true^active=true on sys_script). For each one, record the table, the condition, the purpose, who is exempt, and whether it guards on interactive sessions.

  2. Classify. Separate security rules from convenience rules, conditions the condition builder can express from OR-based or heavily scripted logic, and rules tied to domain separation.

  3. Translate. Create one inactive filter per eligible rule, use dynamic conditions such as "is one of my groups" rather than hard-coded values, and express exemptions with a security attribute in Unless mode.

  4. Measure and test. Run the performance analysis tool on realistic queries. In a sub-production instance, test each persona across lists, forms, workspaces, portal, reports, exports and the REST Table API, including parent-table and indirect-reference paths. Check that scheduled jobs and integrations still see what they should.

  5. Switch. Activate the filter and deactivate, rather than delete, the business rule. Convert the user-facing GlideRecord queries found in step 4 to GlideRecordSecure, monitor, then retire the old rule.

Key takeaways

Migrating to Security Data Filters is worth it for rules whose purpose is security and whose logic fits in a condition: you gain a mechanism designed for the job, readable governance, and a built-in way to measure performance.

It is not a mechanical rewrite. OR-based or heavily scripted rules may have to stay or be redesigned, and the change of default behavior on GlideRecord must be handled explicitly. Treat the migration as a security project: inventory, classify, test every access path, then switch.

Yancoubou Gassama

Yancoubou Gassama

ServiceNow Senior Consultant

ServiceNow Consultant