Skip to main content

SF-0341 · Concept · Medium

What are trigger handlers?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

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.