Read the screenplay: FANNIEGATE — $7 trillion. 17 years. The biggest fraud in American capital markets.
ApexIntermediate2026-03-04

Apex Bulkification: The Only Pattern You Need to Memorize

Every Apex developer learns "don't put SOQL in a loop" on day one. But bulkification goes deeper than that. The real pattern is: collect, query, map, process, DML. Every trigger handler, every batch class, every queueable should follow this exact sequence. Once you internalize it, you will never hit a governor limit again.

Collect means gathering the IDs or field values you need from Trigger.new. Query means doing a single SOQL query using an IN clause with those collected values. Map means putting the query results into a Map<Id, SObject> for O(1) lookups. Process means looping through Trigger.new and using the map to enrich each record. DML means collecting all records to insert/update into a list and doing one DML operation at the end.

This pattern scales from 1 record to 10,000. The number of SOQL queries and DML statements is always constant regardless of batch size. I have used this exact pattern in every trigger handler at Mobilization Funding and Cloud Nimbus. It is boring. It is repetitive. It works every single time.

Code Example

// The Collect-Query-Map-Process-DML pattern:

public class OpportunityTriggerHandler {
  public static void afterUpdate(
    List<Opportunity> newList,
    Map<Id, Opportunity> oldMap
  ) {
    // 1. COLLECT — gather what you need
    Set<Id> accountIds = new Set<Id>();
    for (Opportunity opp : newList) {
      if (opp.StageName != oldMap.get(opp.Id).StageName) {
        accountIds.add(opp.AccountId);
      }
    }
    if (accountIds.isEmpty()) return; // exit early

    // 2. QUERY — one SOQL, not N
    Map<Id, Account> accountMap = new Map<Id, Account>(
      [SELECT Id, Last_Opp_Stage_Change__c
       FROM Account WHERE Id IN :accountIds]
    );

    // 3. MAP — already done (Map<Id, Account>)

    // 4. PROCESS — enrich using the map
    List<Account> toUpdate = new List<Account>();
    for (Opportunity opp : newList) {
      if (opp.StageName != oldMap.get(opp.Id).StageName) {
        Account acc = accountMap.get(opp.AccountId);
        if (acc != null) {
          acc.Last_Opp_Stage_Change__c = System.now();
          toUpdate.add(acc);
        }
      }
    }

    // 5. DML — one operation, not N
    if (!toUpdate.isEmpty()) {
      update toUpdate;
    }
  }
}

Need this implemented in your org?

I've shipped these patterns in production for 10+ years.

View Consulting →

Enjoyed this? Get more like it.

Glen's Musings — AI, investing, and building things. Occasional. Free.

More Apex Tips