Salesforce Order of Execution: Explained with Examples
When you save a record in Salesforce — whether through the UI, Apex, or an API — a complex chain of events unfolds behind the scenes. This sequence is called the Salesforce Order of Execution.
Understanding this is crucial for every developer or admin, especially when debugging automation issues, building scalable logic, or writing Apex triggers.
Why It Matters
Imagine you have workflows, validation rules, process builders, Apex triggers, and flows — all acting on the same object. If you don’t know the order in which they fire, you risk:
- Data corruption
- Recursion
- Unexpected errors
- Performance issues
Let’s dive into the 21 steps Salesforce follows when a record is inserted, updated, or deleted.
Complete Salesforce Order of Execution (With Examples)
- Load the Original Record (from Database)
Purpose: To compare old values with new values (only during update or delete).
- Example: If you’re updating a contact’s phone number, the original value is fetched first.
- Load New Record Values from the Request
Purpose: Field values from the UI, API, or Apex DML are loaded.
- Example: Phone = ‘999-999-9999’ is set in memory, but not yet saved to the DB.
- Run System Validations
System checks like:
- Required fields
- Field data type
- Field length
- Unique constraints
Example: You cannot insert an Account without a Name.
- Run Before Triggers
before insert, before update, or before delete triggers execute.
- Use Case: You want to populate a field before the record is saved.
apex
trigger AccountTrigger on Account (before insert) {
for(Account acc : Trigger.new) {
acc.Account_Code__c = ‘ACC-‘ + DateTime.now().getTime();
}
}
- Custom Validations
Your configured Validation Rules now fire.
- Example: Prevent Opportunity if Close Date < TODAY().
- Duplicate Rules
Duplicate Rules (if enabled) will run and may block the record.
- Example: Prevent inserting a Lead if Email already exists.
- Save the Record (Not Committed Yet)
Record is now saved to memory (not DB), and Id is generated.
- Note: Only fields modified in before triggers are saved.
- Run After Triggers
after insert, after update, or after delete triggers run.
- Use Case: Create a related Task after an Account is created.
apex
trigger AccountAfterInsert on Account (after insert) {
List<Task> tasks = new List<Task>();
for(Account acc : Trigger.new) {
tasks.add(new Task(Subject=’Welcome Call’, WhatId=acc.Id));
}
insert tasks;
}
- Assignment Rules (for Leads & Cases only)
If enabled, assignment rules assign an owner.
- Example: A new Lead may be automatically assigned to a Sales Rep.
- Auto-Response Rules (for Leads & Cases only)
Sends auto-response email if configured.
- Workflow Rules (and Field Updates)
Workflow Rules are evaluated and actions (Field Updates, Email Alerts, Tasks) are queued.
- Example: Workflow sets Status = ‘In Review’.
Important: Field Updates from workflows re-fire before update & after update triggers again.
- Escalation Rules (Cases only)
If set, evaluates escalation conditions and assigns accordingly.
- Roll-Up Summary Fields Calculation
If parent object has roll-up summary fields, they’re recalculated.
- Example: A new Opportunity updates Total_Opportunities__c on its Account.
- Criteria-Based Sharing Rules Evaluation
Any sharing logic that depends on record fields is re-evaluated.
- Post-Commit Logic Queued
Queued jobs like:
- Process Builder
- Flows
- Entitlements
- Async Apex (Queueable, Future, Batch)
- Email Notifications
These run after the DML transaction is committed.
- DML Committed to the Database
All records and changes are now committed.
- Post-Commit Logic Executes
Now the deferred actions execute:
- Process Builders
- Record-Triggered Flows (After Save)
- @future methods
- Email alerts
- Platform Events
- Criteria-Based Sharing Recalculation
Any record access controlled by field-based sharing is recalculated.
- Rollback (If Errors Occur)
If any part fails, Salesforce rolls back the whole transaction.
Recursive Trigger Example
Let’s say:
- You update a custom field via Workflow.
- That triggers a before update trigger again.
- Your trigger then calls update record again… and BOOM 💥 — recursion.
Prevent with:
apex
if(!alreadyExecuted){
alreadyExecuted = true;
// logic here
}
Test Class Best Practice
When writing test classes, simulate different parts of the execution like:
- Insert (to trigger both before insert and after insert)
- Update (to check recursive logic)
- Trigger workflows with field updates and assert values
Summary Table
Step | Automation Type | Executes In |
4 | Before Trigger | Pre-save |
5 | Validation Rules | Pre-save |
8 | After Trigger | Post-save |
11 | Workflow Rules | Post-save |
15 | Process Builder | Post-commit |
17 | Flows, Future | Post-commit |
Common Pitfalls
- Inserting record with an Id set: Use update, not insert
- Infinite loops: Always add static flag logic
- Misplacing logic in after triggers: You can’t modify Trigger.new in after triggers
Final Tips
- Use before triggers to validate or modify values.
- Use after triggers for actions that depend on record Ids (like child record creation).
- Test all automation (Flows, Workflows, Triggers) together — not in isolation.