Skip to main content

SF-0273 · Scenario · Medium

Which DML is recommended ? SINGLE or BULK?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

Bulk every time. A single insert someList is dramatically faster, uses one DML statement instead of N, and survives governor limits that single-record DML in a loop breaches on day one.

Why bulk wins on every axis

Governor limits

Salesforce caps you at 150 DML statements per transaction. A list of 200 records updated one at a time is 200 statements — already failed. One update myList is one statement, regardless of list size (up to 10,000 rows).

Code shapeDML statementsDML rowsOutcome
for (X x : list) update x;200200Fine for 150 records, fails at 151
update list;1200Plenty of headroom — limit is 150 statements, 10k rows

Performance

Single-record DML still goes through the same multi-tenant locking, validation, and trigger pipeline as bulk DML — but you pay that overhead N times. A bulk save invokes triggers once, runs validation in batch, and amortises the round trip.

Transactional integrity

A bulk insert list is one atomic operation: either all records save or none do (unless you opt in to partial success). N single-record DMLs are N separate transactions to the user, but actually run within one Apex transaction — meaning if record 150 fails, records 1-149 are rolled back too, and you’ve still hit the limit.

Trigger semantics

Most Apex triggers are designed to be bulk-safe: Trigger.new is a list, queries use IN :Trigger.newMap.keySet(). Single-record DML inside a loop hands each record to the trigger one at a time, defeating bulkification at every level.

What “bulk DML” looks like

The right shape — build a collection, single DML at the end:

List<Account> toUpdate = new List<Account>();
for (Account a : Trigger.new) {
    if (a.Annual_Revenue__c > 1_000_000) {
        a.Tier__c = 'Enterprise';
        toUpdate.add(a);
    }
}
if (!toUpdate.isEmpty()) {
    update toUpdate;
}

Compare to the antipattern:

for (Account a : Trigger.new) {            // BAD
    if (a.Annual_Revenue__c > 1_000_000) {
        a.Tier__c = 'Enterprise';
        update a;                          // one statement per record
    }
}

“But I only have one record!”

Even then, prefer the list form — it’s the same number of characters and keeps the codebase consistent. Plus, “one record today, 200 tomorrow when someone triggers from a bulk save” is a real risk.

update new List<Account>{ a };

Or use the Database class for explicit control:

Database.update(new List<Account>{ a });

When you do need finer control: Database methods

Sometimes one record’s failure shouldn’t kill the rest. Use Database.insert(list, false) for partial-success semantics:

Database.SaveResult[] results = Database.update(list, false); // allOrNone = false
for (Integer i = 0; i < results.size(); i++) {
    if (!results[i].isSuccess()) {
        Database.Error err = results[i].getErrors()[0];
        // log err.getStatusCode(), err.getMessage()
    }
}

This is still bulk — one DML statement, one trigger pass, full bulkification — but with explicit per-record success reporting.

The 10,000-row hard cap

A single bulk DML statement processes up to 10,000 records. Need more? Use Batch Apex: each execute() chunk is a fresh transaction with its own 10,000-row budget.

What interviewers are really looking for

The answer is “always bulk” — full stop. The senior signal is why: 150-statement limit, 10,000-row limit, one trigger pass, atomic transaction, performance. Bonus: mention Database.update(list, false) for partial-success semantics — useful for data-loader-style imports where one bad row shouldn’t poison the batch. Mention Batch Apex as the answer when the list exceeds 10,000 records and you’ve covered the full progression.

Verified against: Apex Developer Guide — Bulk DML, Execution Governors and Limits. Last reviewed 2026-05-17.