100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Trigger Frameworks

Why orgs adopt a shared trigger handler framework, the core components such frameworks share, and how metadata-driven bypass mechanisms support safe data migrations.

Triggers & LogicAdvanced9 min readJul 10, 2026
Analogies

Why Use a Trigger Framework?

As an org accumulates more objects with trigger logic, teams typically converge on a shared trigger framework - a reusable base handler class that every object-specific handler extends - to avoid re-solving the same problems repeatedly: consistent routing to the correct context method, built-in recursion prevention, and a uniform way to bypass triggers during data migrations or specific automated processes like a mass data-loader run. Without a framework, each new object's trigger tends to reinvent this scaffolding slightly differently, making the codebase harder to maintain as the number of objects grows.

🏏

Cricket analogy: A trigger framework is like a franchise's standardized batting order template that every team in a league like the IPL builds new lineups from, instead of each captain inventing a totally different batting philosophy from scratch every match.

Core Components of a Handler Framework

A typical framework centers on an abstract or virtual base class, often literally named TriggerHandler, that exposes overridable methods like beforeInsert(), afterInsert(), beforeUpdate(), and afterUpdate(), plus a run() or dispatch() method that inspects Trigger.isBefore/isAfter and the relevant event flag to call the correct overridden method automatically. Object-specific handlers, such as AccountTriggerHandler, then extend this base class and override only the specific context methods they actually need, leaving the framework to handle routing, bulk-safety checks, and recursion prevention centrally.

🏏

Cricket analogy: A base handler class with overridable methods is like a national cricket board's standard fielding-drill template that every state team's coach can override with sport-specific variations while the core drill structure stays identical across all teams.

apex
public virtual class TriggerHandler {
    public void run() {
        if (Trigger.isBefore) {
            if (Trigger.isInsert) beforeInsert();
            if (Trigger.isUpdate) beforeUpdate();
        } else if (Trigger.isAfter) {
            if (Trigger.isInsert) afterInsert();
            if (Trigger.isUpdate) afterUpdate();
        }
    }
    protected virtual void beforeInsert() {}
    protected virtual void beforeUpdate() {}
    protected virtual void afterInsert() {}
    protected virtual void afterUpdate() {}
}

public class AccountTriggerHandler extends TriggerHandler {
    protected override void afterInsert() {
        // Account-specific logic only
    }
}

Kevin O'Hara's lightweight TriggerHandler pattern, widely adopted because it's a single Apex class with no external dependencies, focuses purely on context dispatch and simple recursion control via a max-loop-count guard. In contrast, the fflib Apex Enterprise Patterns framework layers triggers on top of a full Domain/Selector/Service architecture, where trigger logic lives in domain classes and is far more testable and decoupled, at the cost of a steeper learning curve and more boilerplate for smaller orgs.

🏏

Cricket analogy: The lightweight TriggerHandler pattern is like a club-level cricket team using a simple, well-worn batting order sheet, while the fflib framework is like an international team's fully staffed analytics department with dedicated roles for every phase of the game.

Choosing between a lightweight pattern like Kevin O'Hara's TriggerHandler and a full enterprise framework like fflib is largely a function of org complexity: a small org with a handful of custom objects rarely needs fflib's Domain/Selector/Service layering, while a large enterprise org managing dozens of interconnected objects benefits from its enforced separation of concerns.

Bypass Mechanisms and Metadata-Driven Control

Mature trigger frameworks expose a bypass or disable mechanism, commonly backed by a Custom Metadata Type record like Trigger_Setting__mdt with a boolean IsActive__c field per object, so an admin or a data-migration script can disable a specific object's trigger without deploying new code, simply by editing the metadata record in Setup or via the Metadata API. This is especially valuable during large one-time data migrations where re-running validation or automation logic on every migrated record would be both unnecessary and dramatically slower.

🏏

Cricket analogy: A bypass mechanism disabling a trigger during migration is like a ground curator temporarily switching off the automatic sprinkler system while resurfacing the pitch, then remembering to switch it back on before the next match or risk a dry, cracked wicket.

Disabling a trigger via a bypass mechanism during a data migration is powerful but dangerous if left on afterward - always pair a bypass with an explicit re-enable step in the same migration script or a scheduled follow-up check, since a silently disabled trigger means all future business logic, like validation or rollups, simply stops firing without any error being thrown.

  • Trigger frameworks provide a reusable base handler class so every object's handler shares consistent context routing and recursion control.
  • A base class typically exposes overridable methods per context (beforeInsert, afterInsert, etc.) with a central dispatch/run method.
  • Kevin O'Hara's lightweight TriggerHandler pattern is a single dependency-free class suited to small and mid-sized orgs.
  • fflib Apex Enterprise Patterns layers triggers onto a full Domain/Selector/Service architecture for large, complex orgs.
  • A Custom Metadata Type-backed bypass mechanism lets admins disable a specific object's trigger without a code deployment.
  • Bypass mechanisms are essential during large data migrations to avoid unnecessary validation/automation overhead on every migrated record.
  • Always pair a trigger bypass with an explicit re-enable step to avoid silently disabling business logic long-term.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#ApexSalesforceStudyNotes#TriggerFrameworks#Trigger#Frameworks#Framework#Core#StudyNotes#SkillVeris#ExamPrep