Learning progress is unavailable. Reading and direct practice remain available; completion controls are disabled.
← Back to Salesforce DevelopmentLesson 3 of 6 · 5–10 minutes including the walkthrough and reflection
Trigger Context & Trigger Design
A trigger is often the first place production business logic enters Apex. Good trigger design starts with the event: what changed, what data is available, and whether the work belongs before save or after save.
The concept
A trigger context tells you where you are in the record lifecycle. Useful working model: before insert - You can set fields on incoming records before Salesforce saves them. - Trigger.new is available. - There is no old version yet. before update - You can compare incoming values with previous values. - Trigger.new and Trigger.old / Trigger.oldMap are available. - Good for validation or normalizing fields on the same records. after insert / after update - The records have been saved and have IDs. - Useful for related-record work, integration handoff, or logic that needs committed record values. - Trigger.new records are read-only in after triggers. before delete / after delete - Trigger.old is available because the records being deleted existed before the operation. - Trigger.new is not available for delete. Design habit: Keep the trigger thin. Let it route to a handler with the relevant context data. Put business logic in methods that can be tested and reasoned about.
Worked example
// ❌ Problematic: business logic grows directly inside the trigger.
trigger AccountTrigger on Account (after update) {
for (Account accountRecord : Trigger.new) {
if (accountRecord.Industry != Trigger.oldMap.get(accountRecord.Id).Industry) {
// More queries, branching, related updates, and rules get added here.
}
}
}
// ✅ Better shape: trigger routes, handler owns the behavior.
trigger AccountTrigger on Account (before update, after update) {
if (Trigger.isBefore && Trigger.isUpdate) {
AccountTriggerHandler.beforeUpdate(Trigger.new, Trigger.oldMap);
}
if (Trigger.isAfter && Trigger.isUpdate) {
AccountTriggerHandler.afterUpdate(Trigger.new, Trigger.oldMap);
}
}
public class AccountTriggerHandler {
public static void afterUpdate(List<Account> newAccounts, Map<Id, Account> oldById) {
Set<Id> changedAccountIds = new Set<Id>();
for (Account accountRecord : newAccounts) {
Account oldAccount = oldById.get(accountRecord.Id);
if (oldAccount != null && accountRecord.Industry != oldAccount.Industry) {
changedAccountIds.add(accountRecord.Id);
}
}
// Related-record work can now be bulkified here.
}
}Field-change detection is a core trigger skill: 1. Read the new value from Trigger.new. 2. Read the previous value from Trigger.oldMap using the same record Id. 3. Compare the field you care about. 4. Do work only when that field changed. That avoids repeating expensive work on every update. For example, if Account.Phone changed but Account.Industry did not, the Contact-description logic should not run. Flow + Apex awareness: Flows, validation rules, and Apex can participate in the same save operation. You do not need to become an automation architect for every trigger, but you should ask: “Could something else update this same record or related records?” That question helps you spot recursion risk and duplicated business rules. Basic recursion awareness: If an after update trigger updates records that cause the same trigger path to run again, you need a deliberate guard or a design that avoids re-entering the same work. Do not hide recursion with a random static flag unless you understand what behavior it prevents.
Common mistake
❌ Common mistake: Using Trigger.oldMap in insert logic or Trigger.new in delete logic without checking the event. Another common mistake: Putting every business rule directly in the trigger. It works at first, but it becomes harder to test, harder to review, and easier to break when another event is added.
Interview angle
🎯 Interview angle Question: “When would you use before update versus after update?” Weak answer: “Before is before save and after is after save.” Stronger answer: “In before update, I can change fields on the records being saved without extra DML and compare new values with Trigger.oldMap. In after update, I use the saved records for related-record work or actions that need record IDs or final saved values. I choose the context based on the side effect I need.”
Pause and apply
🧠 Key takeaway: Event ↓ Available context data ↓ Correct side effect ↓ Thin trigger routes to tested handler Try it yourself: 1. Which context variables would you use to detect that Account.Industry changed? 2. Why is updating the same records usually better in before update than after update? 3. What might happen if Flow and Apex both update the same related Contacts? 4. How would you explain “thin trigger, handler class” without claiming it automatically makes code bulk-safe?
Official references
- Trailhead: Get Started with Apex Triggers (opens in a new tab)
- Apex Developer Guide: Trigger Context Variables (opens in a new tab)
- Apex Developer Guide: Triggers and Order of Execution (opens in a new tab)
Reviewed 2026-09-15. Examples are illustrative; no code is executed here.
Apply it in practice
Apex Trigger Context & DML Fundamentals
Marking a lesson as read records learning activity, not mastery. Practice evidence continues to come from the challenge system.