Trigger Framework Patterns

Overview

A trigger framework enforces consistent, bulk-safe execution by separating trigger entry points from business logic.

The goal is predictable behavior across insert/update/delete contexts with minimal duplicate logic.

Consensus Best Practices

Core Structure

trigger ContactTrigger on Contact (
    before insert, before update,
    after insert, after update
) {
    ContactTriggerHandler.run(Trigger.new, Trigger.oldMap, Trigger.isBefore, Trigger.isInsert);
}
public with sharing class ContactTriggerHandler {
    public static void run(List<Contact> newList, Map<Id, Contact> oldMap, Boolean isBefore, Boolean isInsert) {
        if (TriggerGate.shouldSkip('ContactTrigger')) return;

        if (isBefore && isInsert) handleBeforeInsert(newList);
        else if (isBefore && !isInsert) handleBeforeUpdate(newList, oldMap);
        else if (!isBefore && isInsert) handleAfterInsert(newList);
        else if (!isBefore && !isInsert) handleAfterUpdate(newList, oldMap);
    }

    private static void handleBeforeInsert(List<Contact> rows) { /* validation */ }
    private static void handleBeforeUpdate(List<Contact> rows, Map<Id, Contact> oldMap) { /* diff checks */ }
    private static void handleAfterInsert(List<Contact> rows) { /* enqueue async */ }
    private static void handleAfterUpdate(List<Contact> rows, Map<Id, Contact> oldMap) { /* side effects */ }
}

Recursion and Re-Entry Control

Use a small gate utility keyed by handler/context to avoid duplicate execution in one transaction.

Avoid global static booleans that accidentally suppress valid processing.

Change Detection Pattern

Only execute expensive logic when relevant fields changed:

Common Failure Modes