What is Apex Trigger Framework? What are different Trigger Frameworks available in Salesforce?

Introduction

Apex triggers are essential for implementing business logic that runs before or after DML operations in Salesforce. However, unmanaged trigger logic can quickly become hard to maintain, untestable, and prone to governor limit issues. An Apex Trigger Framework provides a structured, reusable approach to organize trigger code following best practices like single responsibility, bulkification, testability, and separation of concerns.

Why use a Trigger Framework?

Using a trigger framework brings these advantages:

  • Consistent structure across objects and teams
  • Better unit test coverage and easier mocking
  • Reduced risk of hitting governor limits via centralized resource handling
  • Clear separation between trigger orchestration and business logic
  • Improved reusability and easier change management

Common components of a Trigger Framework

Most frameworks include some or all of the following:

  • One trigger per object (dispatcher) that delegates to a handler or domain class
  • Handler classes with methods for each trigger context (before insert, after update, etc.)
  • Domain layer or service layer to encapsulate business logic
  • Unit-of-Work patterns to group DML and reduce callouts
  • Centralized utility for bulk-safe operations and context-specific helpers

Popular Trigger Frameworks and Patterns in Salesforce

1) One Trigger Per Object + Handler Pattern (Simple Handler)

This is the most common, lightweight approach. Each sObject has a single trigger that delegates to a handler class. The handler class exposes methods for trigger contexts (beforeInsert, afterUpdate, etc.). This pattern is simple to implement and easy to follow.

// Account.trigger
trigger AccountTrigger on Account (before insert, before update, after insert, after update, before delete, after undelete) {
AccountTriggerHandler handler = new AccountTriggerHandler();
if (Trigger.isBefore) {
if (Trigger.isInsert) handler.beforeInsert(Trigger.new);
if (Trigger.isUpdate) handler.beforeUpdate(Trigger.new, Trigger.oldMap);
if (Trigger.isDelete) handler.beforeDelete(Trigger.oldMap);
}
if (Trigger.isAfter) {
if (Trigger.isInsert) handler.afterInsert(Trigger.newMap);
if (Trigger.isUpdate) handler.afterUpdate(Trigger.newMap, Trigger.oldMap);
if (Trigger.isUndelete) handler.afterUndelete(Trigger.newMap);
}
}

// AccountTriggerHandler.cls (skeleton)
public with sharing class AccountTriggerHandler {
public void beforeInsert(List newList) {
// business logic
}
public void beforeUpdate(List newList, Map oldMap) {}
public void beforeDelete(Map oldMap) {}
public void afterInsert(Map newMap) {}
public void afterUpdate(Map newMap, Map oldMap) {}
public void afterUndelete(Map newMap) {}
}

2) fflib-Apex-Common (Enterprise Patterns by FinancialForce)

fflib is a well-known, battle-tested library implementing enterprise patterns for Apex: Domain Layer, Service Layer, Unit of Work, Selector, and more. It promotes strong separation of concerns and testability by relying on interfaces and dependency injection.

Pros: scalable for large projects, excellent for multiple developers and complex orgs. Cons: higher learning curve and initial setup overhead.

3) Domain Layer / SObject Domain Pattern

The Domain pattern wraps an sObject in a domain class containing business logic relevant to that object. Triggers delegate to domain instances that orchestrate behavior by calling into services and repositories.

This pattern aligns well with fflib and provides a clean way to group object-specific logic and validation.

4) Centralized Trigger Dispatcher (Multi-Object Framework)

A dispatcher-based framework keeps all trigger orchestration in a central place and registers handlers per object and event. This can simplify enabling/disabling features, controlling execution order, and applying global policies like feature flags or bulk limits.

5) Table-Driven / Metadata-Driven Frameworks (e.g., TDTM in NPSP)

These frameworks use metadata (custom settings, custom metadata, or configuration records) to control which logic runs for an object/event without changing code. The Nonprofit Success Pack (NPSP) uses a Table Driven Trigger Management (TDTM) pattern to enable configurable trigger behavior.

6) Salesforce’s Native Best-Practices (One Trigger Per Object + Utility Libraries)

Salesforce recommends patterns similar to the One Trigger Per Object approach and encourages use of helper classes, keeping logic out of triggers, and ensuring bulkification.

Comparing Frameworks — When to use which

  • Small orgs or simple logic: Use One Trigger Per Object + Handler. Quick to implement, low overhead.
  • Medium orgs with modular requirements: Domain Layer or a lightweight dispatcher gives more structure and testability.
  • Large enterprise or highly complex logic: Use fflib patterns (Domain, UnitOfWork, Selector). This scales best across teams.
  • Configurable behavior required: Consider metadata-driven frameworks like TDTM to enable/disable or configure logic without deployments.

Best Practices for Any Trigger Framework

  • Adopt one consistent pattern across the org — consistency matters more than the specific pattern chosen.
  • Keep triggers thin: delegates to handler or domain classes only.
  • Always bulkify code and avoid row-by-row DML or SOQL inside loops.
  • Use dependency injection and interfaces where possible to make unit testing easier.
  • Implement a Unit of Work to manage DML order and minimize database round trips.
  • Handle recursion and re-entry guards to prevent infinite trigger loops.
  • Write meaningful unit tests and enforce code coverage and behavior assertions.

Conclusion

There is no one-size-fits-all Apex Trigger Framework. Choose a pattern that aligns with your org size, team structure, and application complexity. For most teams, starting with a One Trigger Per Object + Handler approach, then evolving to Domain Layer or adopting fflib when complexity grows, is a pragmatic path.

Keywords: Apex Trigger Framework, Salesforce trigger frameworks, Apex triggers, trigger patterns, fflib, domain layer, unit of work, bulkification, trigger handler.