Why use a trigger framework?
Trigger frameworks bring structure, reusability and testability to Apex triggers. For teams working on medium-to-large Salesforce orgs, ad-hoc triggers quickly become hard to maintain — duplicated logic, order-of-execution surprises, and bulkification bugs are common. A framework enforces patterns such as one-trigger-per-object and delegates business logic to handler classes, which improves readability and reduces deployment risk.
Popular trigger frameworks
Some widely used frameworks and approaches:
- fflib (Apex Common) — A full enterprise pattern library (factory, selector, unit of work) that pairs well with trigger handling.
- Trigger Handler / One Trigger Per Object — Lightweight pattern where the trigger delegates to a handler class (common and recommended).
- Kevin O’Hara / Andrew Fawcett style frameworks — Many community implementations that add features like re-entrancy guards, context helpers, and bulk-safe utilities.
- Declarative alternatives — Record-Triggered Flows for many use cases (but frameworks remain useful for complex logic and integrations).
Typical structure — Trigger delegating to a handler
Below is a minimal example demonstrating the one-trigger-per-object pattern. It keeps the trigger skinny and pushes logic to a handler class which is easier to test and evolve.
// AccountTrigger.trigger
trigger AccountTrigger on Account (before insert, before update, after insert, after update) {
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.isAfter) {
if (Trigger.isInsert) handler.afterInsert(Trigger.newMap);
if (Trigger.isUpdate) handler.afterUpdate(Trigger.newMap, Trigger.oldMap);
}
}
// AccountTriggerHandler.cls
public class AccountTriggerHandler {
public void beforeInsert(List
for (Account a : newRecords) {
if (a.Name == null) a.Name = 'Unknown Account';
}
}
public void beforeUpdate(List
// add validation, mark flags for after actions, etc.
}
public void afterInsert(Map
// perform non-DML operations or callouts queued via future/queueable
}
public void afterUpdate(Map
// handle post-update async work or notifications
}
}
fflib and enterprise patterns
If your org needs robust layering (repositories/selectors, unit-of-work, domain logic), fflib Apex Common is a battle-tested option. It provides a Domain and Service layer and works well with Trigger Handlers to keep triggers thin while enabling complex interactions.
Benefits of using a trigger framework
- Single entry point per object, easier to locate trigger logic.
- Improved testability — handler classes are small and unit-test friendly.
- Consistency — teams follow the same conventions which reduces bugs.
- Bulk-safe patterns and centralised exception handling.
- Better separation of concerns; business rules live in classes, not in triggers.
Common pitfalls & how to avoid them
- Over-engineering — don’t introduce a massively complex framework for a tiny org. Start with a simple handler pattern.
- Order-of-execution surprises — document and control handler execution order if multiple handlers or frameworks are used.
- Governor limits — always bulkify and use collections and maps; prefer a Unit Of Work pattern for grouped DML.
- Re-entrancy — guard against recursive updates using static flags or re-entry checks provided by the framework.
Testing guidelines
Write focused unit tests for handler methods covering bulk scenarios, mixed DML, and edge cases. Use test setup factories (or fflib test factories) to create consistent test data. Keep trigger tests small — validate that trigger delegates and orchestration is correct, but exercise business rules in handler class tests.
When to prefer Flows vs. Triggers
For simple record automation, Record-Triggered Flows are preferred (faster to build, admin-friendly). Use trigger frameworks when you need:
- Complex logic, multiple object interactions or transaction boundaries.
- External integrations, callouts, or patterns not supported by Flow.
- Shared, versioned code and team development workflows.
Quick checklist before adopting a framework
- Assess org complexity and future growth.
- Start with One Trigger Per Object and a simple handler.
- Introduce fflib or a richer framework only when domain layering is needed.
- Train your team and add linting/static analysis rules to enforce conventions.
In summary: yes — I recommend using a trigger framework (even a lightweight handler pattern) for anything beyond trivial automation. It reduces technical debt, improves maintainability, and makes large orgs manageable.
Leave a Reply