A trigger handler is an Apex class that contains the actual business logic a trigger needs to run. The trigger file itself stays one or two lines long — its only job is to detect the context (which event, before/after) and call the right handler method. The handler is plain Apex: easy to test, mock, and reuse.
Why bother with a handler class
A trigger file isn’t a normal Apex class. You can’t unit-test the trigger file in isolation, you can’t instantiate it, and Salesforce makes ordering across multiple triggers on the same object unpredictable. A handler solves all three:
- Testable — handlers are normal classes; tests instantiate them and call methods directly.
- One trigger per object — the handler routes; you never have two triggers competing for order.
- Reusable — multiple triggers (or even other handlers) can call the same method.
- Versionable — wrap the handler in an interface; swap implementations during refactors without touching the trigger file.
Minimal handler pattern
public with sharing class AccountTriggerHandler {
public void run() {
switch on Trigger.operationType {
when BEFORE_INSERT { beforeInsert((List<Account>) Trigger.new); }
when BEFORE_UPDATE { beforeUpdate((List<Account>) Trigger.new, (Map<Id, Account>) Trigger.oldMap); }
when AFTER_INSERT { afterInsert((Map<Id, Account>) Trigger.newMap); }
when AFTER_UPDATE { afterUpdate((Map<Id, Account>) Trigger.newMap, (Map<Id, Account>) Trigger.oldMap); }
}
}
private void beforeInsert(List<Account> newAccounts) {
// Set defaults, derived fields, validate values
}
private void beforeUpdate(List<Account> newAccounts, Map<Id, Account> oldMap) {
// Detect changes, compute deltas
}
private void afterInsert(Map<Id, Account> newMap) {
// Create child records, fire async callouts
}
private void afterUpdate(Map<Id, Account> newMap, Map<Id, Account> oldMap) {
// Roll up to parents, audit, notify
}
}
trigger AccountTrigger on Account (
before insert, before update,
after insert, after update, after delete, after undelete
) {
new AccountTriggerHandler().run();
}
The trigger file is now trivial — one line of real code. All the meat lives in the handler.
Handler frameworks (worth knowing by name)
You don’t have to roll your own. Battle-tested community frameworks:
- kevinohara80/sfdc-trigger-framework — the original community standard. Base class with hook methods you override.
- fflib (Apex Common) — Andrew Fawcett’s enterprise pattern. Heavier but pairs well with full Domain/Service/Selector layering.
- Hari Krishnan’s Trigger Framework — newer, with built-in recursion control and bypass flags.
All three give you free recursion guards, a disable/enable pattern for tests and migrations, and per-context ordering.
Common interview follow-ups
- Why not put everything in the trigger file? — No tests, no mocking, no ordering, no reuse. Every senior reviewer will reject inline trigger logic.
- How is a handler different from a helper class? — A handler is the dispatcher tied to trigger contexts. A helper holds reusable business logic the handler (and other classes) call into. Same code style, different role.
- Should every project use a framework? — For greenfield, yes. For one-off triggers in small orgs, a minimal hand-rolled handler is fine.
Verified against: Apex Developer Guide — Triggers and Best Practices, Trailhead — Apex Triggers Module. Last reviewed 2026-05-17.