Apex triggers are powerful, but they can also become hard to maintain if you don’t follow a few simple rules. These best practices help keep your triggers clean, efficient, and safe for production.
The trigger should only decide what event is running and delegate the work to handler classes. This makes your code easier to test and easier to understand.
trigger AccountTrigger on Account (before insert, before update, after update) {
if (Trigger.isBefore) {
AccountTriggerHandler.beforeSave(Trigger.new, Trigger.oldMap);
}
if (Trigger.isAfter) {
AccountTriggerHandler.afterSave(Trigger.new, Trigger.oldMap);
}
}
Salesforce can process up to 200 records in a single trigger invocation. That means no single-record logic, no SOQL inside loops, and no DML inside loops.
for (Account acc : Trigger.new) {
if (acc.IsActive__c) {
activeAccounts.add(acc);
}
}
List<Account> updates = new List<Account>();
for (Account acc : activeAccounts) {
acc.Description = 'Active account';
updates.add(acc);
}
update updates;
Guard your code with Trigger.isInsert, Trigger.isUpdate, Trigger.isDelete,
Trigger.isBefore, and Trigger.isAfter so each path runs only when it should.
if (Trigger.isBefore && Trigger.isUpdate) {
// validation logic
}
if (Trigger.isAfter && Trigger.isInsert) {
// post-save actions
}
Hard-coding IDs, API names, or object names makes your code brittle and hard to deploy across environments. Use custom settings, custom metadata, or describe calls when needed.
Your tests should cover single record and multiple record scenarios, insert/update/delete flows, and error conditions. This is the only way to catch trigger bugs before deployment.
Good trigger design is mostly about structure and discipline. Keep triggers lean, use handler classes, always support bulk operations, and avoid doing too much in a single trigger.
← Back to Apex