Governor Limits

Catch limit violations
before your deploy does.

Salesforce governor limits are invisible until you hit them in production. Nimbus enforces them locally - the same limits, the same counts, the same errors - so you find out during development, not during a release.

The problem with governor limits

Salesforce enforces resource limits per transaction: 100 SOQL queries, 150 DML statements, 12 MB of heap space. Exceed any of them and Salesforce throws a runtime exception that rolls back your entire transaction. No warning. No partial commit. Just a failure - often in production, after a data volume increase that your tests never exercised.

The problem is that limits don't show up in unit tests at low data volumes. A trigger that runs 3 SOQL queries per record is fine in a test with 10 records. In production with 200 records in a single batch, it blows past the limit on the first bulkified operation. Your 95% test coverage didn't catch it because your tests never pushed the boundaries.

Without local execution, you have no way to observe limit consumption during development. You deploy, you find out. With Nimbus, you find out locally.

apex
// This trigger looks fine in a single-record test
trigger AccountTrigger on Account (before insert) {
    for (Account acc : Trigger.new) {
        // ❌ SOQL inside a loop - 1 query per record
        List<Contact> contacts = [
            SELECT Id FROM Contact WHERE AccountId = :acc.Id
        ];
        acc.Contact_Count__c = contacts.size();
    }
}

// With 10 records: 10 SOQL queries - passes
// With 101 records: 101 SOQL queries - System.LimitException
// nimbus test (strict mode): fails immediately, points at the loop

Three enforcement modes

Not every context needs the same level of enforcement. Local development benefits from fast feedback without blocking on every limit. CI should be strict - it's your quality gate. Nimbus gives you control through the nimbus.governor.mode setting.

strict

Fail the test

Exceeding a limit fails the test immediately with a System.LimitException, exactly as Salesforce would. Use this in CI to enforce limits as a quality gate before every merge.

warn

Log a warning

The test continues but a warning is printed. You see where the violation happened without the test failing. Good for local development - you're aware of limits without being blocked.

off

Ignore limits

No limit tracking. Useful when writing tests for code that intentionally exceeds limits (to verify your exception handling), or when debugging unrelated issues and limits are noise.

Different modes for different contexts

The right configuration: warn locally so you stay informed without being blocked, and strict in CI so limit violations never reach main.

Use Nimbus's profile system to define this once, in your committed nimbus.properties file. Set NIMBUS_PROFILE=ci in your pipeline. No wrapper scripts, no per-developer configuration, no drift.

The off mode is also useful in a dedicated profile when testing exception-handling paths that expect a limit to be hit -NIMBUS_PROFILE=limits-off nimbus test ExceptionTest.

properties
# nimbus.properties

# Local: warn on violations, stay unblocked
nimbus.governor.mode=warn

# CI: strict enforcement, fail on any violation
%ci.nimbus.governor.mode=strict

# Optionally tune the limits themselves
# (defaults match Salesforce's synchronous limits)
nimbus.governor.soql-queries=100
nimbus.governor.dml-statements=150
nimbus.governor.heap-size=12000000
bash
# Local development - violations warn, don't fail
nimbus test

# CI - violations fail the test
NIMBUS_PROFILE=ci nimbus test

# One-off: run with strict mode for a check
nimbus test --governor-mode strict

What gets tracked

Nimbus tracks governor limit consumption per transaction and resets counters between tests. Each test method runs in full isolation - limits from one test don't bleed into the next.

PropertyDefaultDescription
nimbus.governor.soql-queries100SOQL queries per transaction
nimbus.governor.dml-statements150DML statements per transaction
nimbus.governor.heap-size12000000Heap size in bytes (12 MB)
Limits.getLimitQueries()-Read current limit in Apex - works the same as in a real org
Limits.getQueries()-Read current consumption - test your own governor-aware code

Testing your own governor-aware code

Code that checks Limits.getQueries() and adjusts behavior accordingly can be tested locally too. Nimbus tracks consumption faithfully, so assertions against limit values behave exactly as they would in an org.

apex
@isTest
static void testGovernorAwareBulkOperation() {
    // Verify your service respects query limits
    List<Account> accounts = new List<Account>();
    for (Integer i = 0; i < 50; i++) {
        accounts.add(new Account(Name = 'Test ' + i));
    }
    insert accounts;

    Integer queriesBefore = Limits.getQueries();
    BulkAccountService.processAll(accounts);
    Integer queriesUsed = Limits.getQueries() - queriesBefore;

    // Assert bulkification: should be 1 query for 50 records, not 50
    System.assert(queriesUsed <= 3,
        'Expected bulkified queries, got ' + queriesUsed);
}

Common patterns that hit limits

SOQL in a loop

The classic governor violation. One query per record in Trigger.new blows the limit at 101 records.

apex
// ❌ 1 query per record
for (Account acc : Trigger.new) {
    List<Contact> c = [SELECT Id FROM Contact
                        WHERE AccountId = :acc.Id];
}

// ✓ 1 query total
Set<Id> ids = new Map<Id, Account>(Trigger.new).keySet();
Map<Id, List<Contact>> cMap = new Map<Id, List<Contact>>();
for (Contact c : [SELECT Id, AccountId FROM Contact
                  WHERE AccountId IN :ids]) {
    if (!cMap.containsKey(c.AccountId))
        cMap.put(c.AccountId, new List<Contact>());
    cMap.get(c.AccountId).add(c);
}

DML in a loop

One DML per record is the most common bulkification mistake. Collect records and issue a single DML statement.

apex
// ❌ 1 DML per record
for (Account acc : accounts) {
    acc.Status__c = 'Active';
    update acc;
}

// ✓ 1 DML total
for (Account acc : accounts) {
    acc.Status__c = 'Active';
}
update accounts;

Find limit violations in development.

Not in production. Governor limits enforced locally - the same limits, the same counts, the same exceptions - before the code ever reaches an org.