Its_Azar
Kilo Sage

Let’s talk about something that’s been around forever in ServiceNow development — Async vs Before Business Rules. It’s one of those topics that everyone nods at confidently. “Yeah yeah, I know the difference.” But if you spend enough time reviewing code on real projects, you’ll notice even very experienced developers still get this wrong. Not because they don’t understand the basics — but because they underestimate the impact of where logic runs.

 

b195d547-87cf-47e9-a381-bc934df7e2e1.png

 

On paper, the difference is simple. A Before Business Rule runs before the record is committed to the database. It’s part of the same transaction. It can modify current, it can block the save, and whatever it does becomes part of that atomic operation. Async, on the other hand, runs after the record is committed. It’s scheduled in the background. It doesn’t block the user. It doesn’t influence whether the save succeeds. It just… happens later.

 

That difference sounds small. Architecturally, it’s massive.

The most common thing I see is heavy logic shoved into Before rules. Big loops. Multiple GlideRecord queries. Cross-table updates. Sometimes even outbound REST calls. And technically? It works. The record saves. The logic runs. Everyone’s happy — until users start complaining that saving a form feels slow. Or worse, intermittent performance issues start appearing and nobody can immediately pinpoint why. The truth is simple: if your Before rule takes three seconds to run, the user waits three seconds. Every single time. Multiply that by hundreds of users and you’ve just created unnecessary load and friction.

 

Then there’s the opposite problem — pushing logic into Async that actually needs transactional integrity. I’ve seen derived fields, critical calculations, and state management handled asynchronously because “it’s better for performance.” But here’s the catch: async runs after the commit. That means the UI might briefly show stale data. Reports might run before the async job finishes. Integrations might fire based on incomplete information. You don’t always notice it immediately, but you’ve introduced inconsistency into your system. And inconsistency is way harder to debug than a slow form.

 

Async also creates a subtle complexity that people don’t talk about enough: timing. When a record gets updated multiple times quickly, multiple async jobs get queued. They don’t necessarily execute in the order you expect. They don’t freeze the record’s state in time. By the time your async rule runs, the record may have changed again. If your logic assumes it’s operating on a stable snapshot, you’re already in dangerous territory. That’s how race conditions creep in — quietly.

 

Another pattern I keep running into is async rules updating the same table without guardrails. It feels harmless. “I’ll just update this field in the background.” But that update triggers business rules again. And if conditions aren’t tight, you’ve accidentally built a recursion engine. It might not infinite-loop dramatically — sometimes it just doubles or triples the workload silently. Those are the worst kinds of problems because nothing crashes. It just gets heavier and heavier.

 

What it really comes down to is understanding intent. Before rules exist to protect correctness at the moment of commit. They’re about integrity. If something must be true when the record is saved — validation, normalization, essential derived values — it belongs there. Async rules exist to protect performance and scalability. They’re for enrichment, notifications, integrations, non-critical secondary updates. When you mix those responsibilities, you compromise both integrity and performance.

The tricky part is that bad placement doesn’t always break immediately. In small environments, everything feels fine. Low data volume hides inefficiencies. Limited concurrency masks race conditions. But once you scale — more users, more updates, more integrations — those architectural shortcuts surface. And by then, they’re baked into core logic.

 

The difference between a stable enterprise instance and a fragile one usually isn’t syntax or scripting skill. It’s execution context discipline. Knowing not just how to write the logic — but where it should run. Just some casual ranting about a few code checks, haha, hope this was useful.