SuiteScript Governance — What You Actually Need to Know

Governance limits are the #1 reason SuiteScript fails in production. How they work, what they cost, and how to not run out.

TL;DR: Every SuiteScript gets a governance budget. Each API call costs units. Run out and the script dies. The fix is almost always architectural — batch your operations, use Map/Reduce for heavy lifting, cache what you can, check remaining units before expensive calls.


If you have written SuiteScript for any length of time, you have hit a governance error. Yep, most common production issue I see. And most of the time, the root cause is the same — the script is doing too much work in the wrong way.

How it works

NetSuite gives every script execution a fixed budget of "governance units." Every API call — loading a record, running a search, sending an email — costs some of those units. Run out and the script stops. No warning, no graceful degradation. It just stops.

That's NetSuite protecting its shared infrastructure. Reasonable constraint, but you need to design around it.

The costs that matter

Operations you will use most and what they cost:

  • record.load() — 10 units
  • record.submit() — 20 units
  • search.run().each() — 10 units per search
  • https.get() / https.post() — 10 units
  • email.send() — 20 units
  • record.transform() — 10 units

And here is how much budget you get:

Script Type Governance Limit
Client Script 1,000 units
User Event 1,000 units
Suitelet 1,000 units
RESTlet 5,000 units
Scheduled 10,000 units
Map/Reduce 10,000 per phase

Look at those numbers. A User Event with 1,000 units can load about 100 records before it dies. If you are looping through order lines and loading related records for each one, you are going to have a bad time on any order with more than a few dozen lines.

What to do about it

1. Stop loading records in loops

Most common mistake I see (and I have seen a lot of these). Use a search instead of record.load() inside a loop.

// This will blow up on large datasets
orderIds.forEach((id) => {
    const rec = record.load({ type: 'salesorder', id });
    // ... process
});

// Do this instead
const results = search.create({
    type: 'salesorder',
    filters: [['internalid', 'anyof', orderIds]],
    columns: ['entity', 'total', 'status']
}).run().getRange({ start: 0, end: 100 });

One search = 10 units. Loading 100 records individually = 1,000. The math is obvious.

2. Use Map/Reduce for heavy lifting

Processing thousands of records? Do not try to cram it into a Scheduled Script. Map/Reduce gives each phase its own governance budget and NetSuite handles the parallelism. That's what it is built for.

3. Check remaining units

Before anything expensive, check if you can afford it:

const remaining = runtime.getCurrentScript().getRemainingUsage();
if (remaining < 200) {
    log.audit('Low governance', `Only ${remaining} units left`);
    // Bail out or reschedule
}

Especially important in Scheduled Scripts processing batches. Know when to stop and yield (your future self will thank you when it does not crash in production at 2am).

4. Cache configuration data

Loading the same setup record on every execution? Use N/cache. One load + cache hits is always cheaper than loading the same record hundreds of times.

The real lesson

Script runs out of governance — the first question should not be "how do I get more units?" It should be "why am I using so many?"

Almost every case I have seen across hundreds of projects — governance problems point to an architecture issue. Fix the design and the problem goes away. That simple.