Data Manipulation Language (DML)
Data Manipulation Language (DML) in Salesforce is the set of Apex statements and operations that create, update, delete, undelete, merge, or upsert records in the Salesforce database.
Definition
Data Manipulation Language (DML) in Salesforce is the set of Apex statements and operations that create, update, delete, undelete, merge, or upsert records in the Salesforce database. The core DML statements are insert, update, delete, undelete, merge, and upsert, applied either as bare statements on a single sObject or list of sObjects, or as Database methods (Database.insert, Database.update, etc.) that return Result objects with per-record success and error information. DML is how Apex code modifies data in Salesforce; SOQL reads, DML writes.
DML in Apex is similar in spirit to SQL DML in traditional databases but has Salesforce-specific constraints. Every DML operation runs inside an Apex transaction, is bound by Salesforce governor limits (most importantly 150 DML statements per transaction), and triggers downstream automation: validation rules, triggers, workflow rules, processes, Flows, and any other configured automation cascade from the DML write. Apex developers spend significant effort planning DML to stay within limits and to handle the cascading side effects correctly.
How DML works in Apex
The DML statements: insert, update, delete, upsert, merge, undelete
Six DML statements cover all data modification. insert creates new records. update modifies existing records. delete moves records to the Recycle Bin. undelete restores deleted records. merge consolidates duplicate records into one. upsert inserts new or updates existing based on an external ID match. Each is available as a bare statement (insert myRecord) or a Database method (Database.insert with optional all-or-none parameter).
Bare DML statements vs Database methods
Bare DML statements treat the operation as all-or-none: if any record fails, the entire transaction rolls back. Database methods support partial success: pass allOrNone=false and the method returns a Result list where some records succeeded and some did not. Database methods are the right pick for bulk operations where some failures are expected and acceptable.
DML governor limits
Salesforce caps DML at 150 statements per transaction and 10,000 total records per transaction (across all statements). Hitting either limit aborts the transaction. The classic anti-pattern is DML inside a loop: 200 records times 1 DML each equals 200 statements, exceeding the cap. The fix is bulkification: collect into a list and execute one DML statement on the whole list.
Cascading automation from DML
Every DML write triggers downstream automation. Validation rules fire first; if they fail, the record save is blocked. Before triggers run on the in-memory record. The database write happens. After triggers, workflow rules, processes, and Flows run in turn. Each automation can itself perform DML, which counts against the same transaction limits. Complex orgs hit cascading DML limits frequently.
Upsert and external ID matching
Upsert is the import-friendly variant. Pass an external ID field; for each record, Salesforce checks if that external ID exists. If yes, update. If no, insert. The pattern fits nightly imports from an ERP where some records are new and some have been seen before. Upsert is also the most common cause of "duplicate external ID" errors when the source system sends two records with the same external ID in one upsert call.
Mixed DML errors and the Mixed DML Exception
Salesforce restricts certain combinations of DML in a single transaction. The classic case: you cannot insert a User and then insert another sObject like Account in the same transaction without using @future or a similar async path. This is the Mixed DML Exception. Setup objects (User, UserRole, Group) and non-Setup objects (Account, Contact, custom objects) cannot be mixed.
Best practices for DML in Apex
Bulkify everything: collect records into lists, then DML once. Use Database methods with partial success for batch operations. Catch DmlException and log meaningful errors. Watch for cascading limits; document complex automation chains. Test with realistic record volumes (200 per trigger call). Use upsert with external ID for repeatable imports.
How to write DML in Apex correctly
The DML statements are simple; the discipline is in bulkification, error handling, and respecting governor limits.
- Build a list, do not DML in a loop
Wrong: for (Lead l : leads) { update l; }. Right: List<Lead> toUpdate = new List<Lead>(); for (Lead l : leads) toUpdate.add(l); update toUpdate. One DML statement covers all records.
- Use Database methods for partial success
Database.SaveResult[] results = Database.update(records, false). Loop the results to find which records failed and why. Critical for batch imports where some records will inevitably fail.
- Handle DmlException correctly
Wrap DML in try-catch (DmlException e). Log the record IDs and error messages. Decide whether to retry, skip, or fail the whole batch based on the error type.
- Pre-validate when possible
Validation rules fire on DML, but Apex pre-validation (checking required fields, format) before DML produces clearer error messages than letting the platform validation rule fail mid-transaction.
- Use upsert for repeatable imports
When loading data from an external system, define an external ID field and use upsert. New rows insert; existing rows update. Avoids duplicate detection logic.
- Test with bulk data
Apex unit tests should insert 200+ records in setup and run the triggered code on the full set. Tests that only exercise 1 record miss bulkification bugs that fail in production.
- DML inside a loop fails on bulk data. Build a list, then DML once. This is the most common Apex bug.
- Governor limits: 150 DML statements, 10,000 records per transaction. Hitting either aborts the entire transaction.
- Mixed DML Exception: cannot insert User and Account in the same transaction without async. Set up affected objects need @future.
- DML triggers cascading automation. A single update can fire triggers, workflows, processes, Flows; all counting against the same limits.
- Upsert requires a unique external ID. Sending two records with the same external ID in one upsert call throws DUPLICATE_EXTERNAL_ID.
Trust & references
Cross-checked against the following references.
- Apex DML StatementsSalesforce Developers
- Database Apex Class MethodsSalesforce Developers
Straight from the source - Salesforce's reference material on Data Manipulation Language (DML).
- Apex Developer GuideSalesforce Developers
- Apex Governor LimitsSalesforce Developers
Hands-on resources to go deeper on Data Manipulation Language (DML).
About the Author
Dipojjal Chakrabarti is a B2C Solution Architect with 29 Salesforce certifications and over 13 years in the Salesforce ecosystem. He runs salesforcedictionary.com to help admins, developers, architects, and cert/interview candidates sharpen their fundamentals. More about Dipojjal.
Test your knowledge
Q1. What does DML stand for?
Q2. What's the DML statement limit per transaction?
Q3. What's the difference between DML statements and Database class methods?
Discussion
Loading discussion…