Triggers come up in the technical round for every Salesforce Developer role, usually right after the Apex basics are cleared. The panel is not testing whether you can write trigger AccountTrigger on Account. They are testing whether you know when your code runs, what runs before it, what runs after it, and what you do when it does not run at all. This post covers ten questions from real interview rounds: trigger frameworks, trigger contexts, before versus after behaviour, recursion, the full order of execution, and the declarative automation that sits around your trigger and fights with it.
Trigger design and context
What is a Trigger Framework?
A trigger framework is a code pattern that keeps all logic out of the trigger file itself. The trigger becomes one line that hands control to a dispatcher, the dispatcher works out which context fired, and a handler class holds the actual business logic.
You need it because logic in a .trigger file cannot be inherited, mocked or unit tested in isolation, and because without a central entry point there is nowhere to put a switch that disables automation during a data load.
A minimal framework has three parts: an interface that defines the context methods, a dispatcher that routes on Trigger.operationType, and one handler per object.
public interface ITriggerHandler {
Boolean isDisabled();
void beforeInsert(List<SObject> newList);
void beforeUpdate(List<SObject> newList, Map<Id, SObject> oldMap);
void beforeDelete(Map<Id, SObject> oldMap);
void afterInsert(Map<Id, SObject> newMap);
void afterUpdate(Map<Id, SObject> newMap, Map<Id, SObject> oldMap);
void afterDelete(Map<Id, SObject> oldMap);
void afterUndelete(Map<Id, SObject> newMap);
}
public class TriggerDispatcher {
public static void run(ITriggerHandler handler) {
if (handler.isDisabled()) {
return;
}
switch on Trigger.operationType {
when BEFORE_INSERT { handler.beforeInsert(Trigger.new); }
when BEFORE_UPDATE { handler.beforeUpdate(Trigger.new, Trigger.oldMap); }
when BEFORE_DELETE { handler.beforeDelete(Trigger.oldMap); }
when AFTER_INSERT { handler.afterInsert(Trigger.newMap); }
when AFTER_UPDATE { handler.afterUpdate(Trigger.newMap, Trigger.oldMap); }
when AFTER_DELETE { handler.afterDelete(Trigger.oldMap); }
when AFTER_UNDELETE { handler.afterUndelete(Trigger.newMap); }
}
}
}
The isDisabled() check normally reads a custom metadata type or a hierarchy custom setting, so an admin can switch off Account automation for a migration without a deployment. Mention that in the interview. It is the part that shows you have run a data load in a real org.
What are Trigger contexts?
A trigger context is the combination of timing (before or after) and operation (insert, update, delete, undelete). Seven combinations exist, and each one gives you a different set of context variables.
| Context | Trigger.new | Trigger.old | Trigger.newMap | Trigger.oldMap | Fields writable |
|---|---|---|---|---|---|
| before insert | Yes | No | No | No | Yes |
| before update | Yes | Yes | Yes | Yes | Yes |
| before delete | No | Yes | No | Yes | No |
| after insert | Yes | No | Yes | No | No |
| after update | Yes | Yes | Yes | Yes | No |
| after delete | No | Yes | No | Yes | No |
| after undelete | Yes | No | Yes | No | No |
Two entries in that table catch people out. Trigger.newMap is not available in before insert, because the records have no Id yet and a map keyed on Id would be meaningless. And Trigger.old never exists on insert, because there is no prior version of the record.
The other context variables worth naming are Trigger.isExecuting, Trigger.size and Trigger.operationType, which returns a System.TriggerOperation enum value and is what the dispatcher above switches on.
This is where a common interview question lands: your trigger is not firing, what do you check? Candidates who only memorised definitions go quiet here. Work through it out loud in this order.
- Is the trigger active? Check the Status checkbox on the trigger in Setup, in the org you are actually testing in.
- Is the operation the one you coded for? A developer writes
after insert, the integration sends an upsert that matches an existing record, and the record updates instead of inserting. - Is a bypass switch on? If your framework reads a custom setting, check the value for the running user, not just the org default.
- Is the code exiting early? Put the debug statement on the first line of the handler method, before every
if. If the log shows entry but no output, the trigger is firing and your filter logic is wrong. - Are you reading the right log? Set the trace flag on the user who performs the operation. For an integration that is the integration user, not you. Set the Apex Code level to FINEST, and check whether the log was truncated before your line.
- Is the operation one that does not fire triggers? Child records removed by a master-detail cascade delete do not run their own delete triggers, and a roll-up summary recalculation on a parent does not fire the parent's update trigger.
- Did something before you block the save? A required field, a validation rule or a duplicate rule with a block action stops the transaction before after triggers run.
Difference between Before vs After triggers
A before trigger runs after the record is loaded and populated in memory but before it is written to the database. An after trigger runs once the row is in the database, inside the same uncommitted transaction.
| Point | Before trigger | After trigger |
|---|---|---|
| Record Id on insert | Not yet assigned | Assigned |
| Fields in Trigger.new | Writable | Read only |
| Extra DML to change the same record | Not needed | Required |
| Related record access by Id | Not possible on insert | Possible |
| Typical use | Defaulting and validating fields on the record itself | Creating or updating other records, sending events, rolling up to parents |
Why are fields writable in before and not in after? In a before trigger, the platform has built an in-memory copy of the record and has not written it yet. Whatever sits in Trigger.new at the end of your code is what gets saved, so assigning a value costs you nothing extra. No DML, no extra save cycle, no governor limit consumed.
By the time an after trigger runs, the row has already been written in step 7 of the save order. Trigger.new is now a read-only snapshot of what is in the database, and assigning to a field there throws a runtime error saying the record is read only. To change the same record from an after trigger you have to issue a separate DML statement, which sends that record through the entire save order again, triggers included.
That drives the rule every senior developer states: if you are only setting fields on the record that fired the trigger, use before. Reach for after only when you need the Id or need the row to exist.
How do you avoid recursive triggers?
Recursion happens when your trigger performs DML that causes the same trigger to fire again. The classic version is an after update trigger on Account that updates the Account, or a pair of triggers on Account and Contact that each update the other. Apex stops you at sixteen levels of recursive DML with a maximum trigger depth exceeded error, but you usually hit the SOQL or DML governor limit first.
The standard defence is a static variable. Static state lives for the length of the transaction and resets on the next one, which is exactly the scope you want.
public class AccountTriggerHelper {
@TestVisible
private static Boolean syncHasRun = false;
public static void syncPrimaryContact(List<Account> accounts) {
if (syncHasRun) {
return;
}
syncHasRun = true;
// rest of the logic, safe from re-entry
}
}
A plain boolean is blunt. It blocks the second run for every record in the transaction, so a second batch of 200 records in the same transaction gets skipped too. The safer pattern tracks the record Ids already handled.
public class RecursionGuard {
private static Map<String, Set<Id>> processedByKey = new Map<String, Set<Id>>();
public static Set<Id> claim(String key, Set<Id> candidateIds) {
if (!processedByKey.containsKey(key)) {
processedByKey.put(key, new Set<Id>());
}
Set<Id> alreadyDone = processedByKey.get(key);
Set<Id> toProcess = new Set<Id>(candidateIds);
toProcess.removeAll(alreadyDone);
alreadyDone.addAll(toProcess);
return toProcess;
}
}
The handler calls RecursionGuard.claim('AccountSync', Trigger.newMap.keySet()) and works only on the Ids returned. Record 1 is never processed twice, and record 201 arriving later in the same transaction is still processed once.
Two habits reduce recursion before any guard is needed. Compare old and new values and exit when the field you care about has not changed. And do same-record field updates in a before trigger, where no DML is issued at all.
How do you handle multiple triggers on same object?
You do not. One trigger per object is the rule, and the interviewer expects you to say it without hedging.
Salesforce gives no guarantee about the order in which two triggers on the same object execute. It is not alphabetical, not by created date, and not documented. So if AccountValidation sets a field that AccountRollup reads, the behaviour works in the sandbox, survives testing, and breaks in production after an unrelated deployment reorders them.
One trigger per object plus a dispatcher fixes it, because the order is now written in your handler code where anyone can read it.
trigger AccountTrigger on Account (
before insert, before update, before delete,
after insert, after update, after delete, after undelete
) {
TriggerDispatcher.run(new AccountTriggerHandler());
}
public class AccountTriggerHandler implements ITriggerHandler {
public Boolean isDisabled() {
Automation_Setting__c setting = Automation_Setting__c.getInstance();
return setting != null && setting.Disable_Account_Trigger__c;
}
public void beforeUpdate(List<SObject> newList, Map<Id, SObject> oldMap) {
List<Account> accounts = (List<Account>) newList;
Map<Id, Account> oldAccounts = (Map<Id, Account>) oldMap;
AccountNamingService.standardiseName(accounts);
AccountOwnerService.stampOwnerRegion(accounts, oldAccounts);
}
// remaining context methods
}
When you inherit an org that already has four triggers on Account, the honest answer is a phased merge: move the body of each trigger into a service class, call those classes from one handler in a deliberate order, then deactivate the old triggers rather than deleting them until the release is stable. Say that. It shows you have worked on an existing org, not only on a training playground.
What the interviewer is actually checking on trigger design
- Whether you can explain why one trigger per object matters, not just state the rule.
- Whether you know which context variables exist in which context, without looking it up.
- Whether you reach for a before trigger when the update is on the same record.
- Whether you have a recursion story from a real problem, not a memorised boolean flag.
- Whether you can debug. Interviewers now ask what you check when a trigger does not fire, because it separates people who have run code in an org from people who have read about it.
The order of execution
What is Order of Execution?
The order of execution is the fixed sequence Salesforce follows every time a record is saved. It is the single most asked question in this section, and it is the one that exposes candidates who know syntax but not execution. Give the ordered list.
- The original record loads from the database, or the record is initialised for an upsert.
- New field values from the request overwrite the old values on the in-memory record.
- Record-triggered flows configured to run before the record is saved execute.
- All before triggers execute.
- System validation runs again: required fields, field formats, maximum lengths, plus all custom validation rules. Layout-specific rules from a UI edit page are the only check not repeated.
- Duplicate rules execute. A duplicate rule set to block stops the save here, and nothing after this point runs.
- The record is saved to the database, but not committed.
- All after triggers execute.
- Assignment rules execute.
- Auto-response rules execute.
- Workflow rules execute.
- If a workflow rule contains a field update, the record is updated again.
- If a workflow field update changed the record, before update and after update triggers fire one more time, and only one more time, along with standard validations. Custom validation rules, duplicate rules and escalation rules do not run again.
- Processes and flows launched by process actions execute. Any DML they perform sends the affected record through this whole save order from the start.
- Escalation rules execute.
- Record-triggered flows configured to run after the record is saved execute. Their DML also sends affected records through the full save order.
- Entitlement rules execute.
- If the record has a roll-up summary field, or is part of a cross-object workflow, the parent is recalculated and saved. The parent goes through the save order itself.
- If the parent was updated and a grandparent holds a roll-up summary, the grandparent is recalculated and saved the same way.
- Criteria based sharing rules are evaluated.
- All DML is committed to the database.
- Post-commit logic runs: emails, queueable jobs, future methods, and asynchronous paths in record-triggered flows.
Four consequences are worth stating after the list. Reciting twenty-two steps proves memory. Explaining the consequences proves understanding.
Before-save flows are the cheapest same-record automation there is. They run at step 3, ahead of everything, and like a before trigger they set fields without a second save. Replacing a workflow field update with a before-save flow removes steps 12 and 13 from the transaction.
Validation rules run after your before trigger. So a before trigger that sets a field to a value the validation rule rejects will block the save, and the error looks like a user error. That confuses people for hours.
Roll-up summary recalculation at step 18 does not fire triggers on the parent. If your parent-level logic depends on a roll-up field, a trigger on the parent will not see the change. Put the logic on the child, or use an Apex-calculated field on the parent.
Criteria based sharing is recalculated late, at step 20. Record access granted by a sharing rule is therefore not reliable inside your after trigger in the same transaction.
Keep the list in your own words. Candidates who recite it flatly get one follow-up question, usually "where does a before-save flow sit and why does that matter", and the recital stops there.
What the interviewer is actually checking on order of execution
- Whether you place before-save flows at the start and after-save flows after workflow rules.
- Whether you know that workflow field updates re-fire update triggers exactly once.
- Whether you understand that roll-ups and criteria based sharing happen near the end.
- Whether you can name what is not repeated on the second trigger pass.
- Whether you can use the list to explain a real bug, which is the only reason anyone learns it.
Declarative automation around the trigger
What is Approval Process?
An approval process is a declarative sequence that routes a record for human approval and records the outcome. It is defined by entry criteria, an approver assignment at each step, and the actions taken on submission, approval, rejection and recall.
Name the pieces in order: entry criteria that decide whether a record can be submitted, initial submission actions, one or more steps with their own criteria and approvers, then the final approval, final rejection and recall actions. Each action slot can run a field update, an email alert, a task or an outbound message.
Two behaviours matter for a developer. The record is locked while it sits in an approval process, so your trigger cannot update it unless the process allows the approver or an admin to edit it. And a field update in an approval action sends the record through the save order again, so your triggers fire on an approval step even though no user edited the record. That is a frequent source of "who changed this field" tickets.
From Apex you submit and act on approvals with the Approval class: build an Approval.ProcessSubmitRequest, set the object Id and comments, and pass it to Approval.process(). The approval history itself is queryable through the ProcessInstance and related step objects, which is what you use to build an approval status component.
What is Escalation Rule?
An escalation rule is case automation that reassigns or flags a case when it has not been resolved within a defined period. It applies to Cases.
A rule holds rule entries. Each entry has criteria deciding which cases it governs, and escalation actions with an age threshold, for example four hours after the case is created or after the last modification. When the clock runs out the action can reassign the case owner, send an email notification and set fields such as priority. The clock can honour business hours, so a case raised at 6pm does not escalate overnight.
Escalation rules appear at step 15 of the order of execution, where the case is matched against the rules and the escalation is scheduled. The escalation action itself fires later, when the age condition is met, and that update then goes through the save order like any other.
In an interview this is usually a check on whether you know the difference between rules that act immediately and rules that act on a clock. Assignment rules act at once, at step 9. Escalation rules set up a future action.
Difference between Workflow Rule and Flow
| Point | Workflow Rule | Flow |
|---|---|---|
| Status | Legacy. New creation is blocked in orgs, and Salesforce is moving existing automation across with the Migrate to Flow tool | Current, and the tool every new automation is built in |
| Actions | Field update, email alert, task, outbound message, time-dependent actions | Create, update, delete and get records on any object, plus screens, subflows, Apex, platform events |
| Records it can touch | The record itself, or its master in a master-detail relationship | Any record it can query |
| Logic | Single criteria set, no branching, no loops | Decisions, loops, collections, formulas, fault paths |
| Timing on the record | Runs at step 11, after the record is saved, and a field update forces a second save | A before-save flow runs at step 3 with no second save |
| Order control | None. Multiple workflow rules on an object have no defined order | Flow Trigger Explorer, plus an explicit trigger order value per flow |
| Error handling | None visible to the builder | Fault paths and fault emails |
| Debugging | Read the debug log | Debug in Flow Builder with real record data |
The performance point is the one that impresses. A workflow field update writes the record, then the platform saves it again at step 12 and re-runs update triggers at step 13. A before-save record-triggered flow sets the same field at step 3 and the record is saved once. On high-volume objects that difference is visible in transaction times.
Do not quote a retirement date from memory in an interview. Say that new Workflow Rules cannot be created, that existing ones still run, and that the direction is to migrate them to Flow, then check Salesforce Help for the current dates before you go in.
How do you stop infinite automation loops?
A loop is any chain where automation on record A updates record B and automation on record B updates record A, or where automation on a record updates that same record and re-enters itself. The platform stops you eventually, with a maximum trigger depth exceeded error at sixteen levels, or a governor limit, or a flow error saying the same record was saved too many times. None of those are good ways to find out.
Work through the fixes in this order.
Only act on real changes. Most loops are caused by automation that runs on every update instead of on the update it cares about. In Apex, compare the old and new value and exit when nothing relevant changed.
public static void handleRatingChange(
List<Account> newAccounts,
Map<Id, Account> oldAccounts
) {
List<Account> changed = new List<Account>();
for (Account acc : newAccounts) {
Account previous = oldAccounts.get(acc.Id);
if (acc.Rating != previous.Rating) {
changed.add(acc);
}
}
if (changed.isEmpty()) {
return;
}
// process only the accounts whose Rating actually moved
}
In a record-triggered flow the same idea is a checkbox: set the entry condition requirements to run the flow only when a record is updated to meet the condition, rather than on every update.
Do same-record updates without DML. A before trigger or a before-save flow writes the field in memory. No second save means no second pass of triggers and flows.
Add a transaction-scoped guard. The static Set of Ids shown earlier stops re-entry even when two objects update each other, because both handlers can share one guard class.
Map the automation before you add more. On an object with several flows and a trigger, open Flow Trigger Explorer and list what writes to which field. Most production loops are two teams automating the same field without knowing about each other.
What the interviewer is actually checking on declarative automation
- Whether you know that approval actions and workflow field updates re-fire your triggers.
- Whether you can place assignment, escalation and workflow rules in the save order.
- Whether you treat Workflow Rules as legacy without inventing a retirement date.
- Whether your first answer on loops is change detection, not a boolean flag.
- Whether you can describe a loop you actually hit and how you traced it.
Prepare the way the round is conducted
The pattern is consistent. The definition question is the opener, and the real question follows it: place this in the order of execution, show me the code, tell me what you checked when it broke. Candidates lose these rounds on demonstration rather than knowledge. They know what a trigger framework is and cannot draw one on a whiteboard.
Fix that with practice rather than more reading. Write the dispatcher from memory. Recite the twenty-two steps, then explain three of them. Take a loop you caused in a developer org and describe it as situation, approach, reason and result, in under ninety seconds.
If you want that practice with feedback on a real org, our Salesforce training in Pune with placement support covers Apex triggers, the order of execution and Flow automation with mock interviews built into the schedule.