Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
A developer reference guide showcasing essential Apex Trigger best practices and syntax, an Apex Trigger Cheat Sheet.
Apex

Apex Trigger Cheat Sheet - Master Salesforce Triggers

Tired of hitting SOQL limits and untangling messy triggers? This Apex Trigger Cheat Sheet covers the context variables, the before and after phases, bulkification, and the handler pattern.

I've spent a lot of time fixing messy Salesforce orgs, and usually the culprit is a trigger someone wrote in a hurry without a plan. This Apex Trigger Cheat Sheet is the reference I keep open to stop code getting messy and deployments failing. Most of it exists because of the "Too many SOQL queries: 101" error you get when a loop wasn't bulkified properly.

Why you need a solid Apex Trigger Cheat Sheet

Triggers are the backbone of serious automation in Salesforce. Flow has gotten much better lately, but there are still plenty of times when you need the speed and control of code. Triggers are also dangerous if you don't follow the rules. If you're deciding between the two tools, this guide on Apex vs Flow covers when code is actually necessary.

A trigger runs in response to DML events like insert, update, delete, or undelete. You have two main windows of opportunity: "before" and "after". Use "before" triggers when you want to update fields on the same record or block a save with an error. Use "after" triggers when you need to create related records or access the ID of the record you just saved.

The Apex Trigger Cheat Sheet: context variables and events

Nobody memorizes every single context variable, but you need to know the heavy hitters. These variables tell your code what is happening right now: are we in an update, and is this the "before" or "after" phase? Here is what you will actually use on a daily basis.

  • Trigger.new: a list of the new versions of the records. Available in insert, update, and undelete.
  • Trigger.old: a list of the old versions of the records. Available in update and delete.
  • Trigger.newMap: a map of IDs to the new records. Useful for looking up related data.
  • Trigger.oldMap: a map of IDs to the old records. Essential for checking if a field value actually changed.
  • Trigger.isBefore / Trigger.isAfter: boolean values telling you which phase you're in.

Basic trigger syntax

Keep your trigger file as simple as possible. You don't want a thousand lines of logic sitting directly in the trigger. Instead, use a structure like this to route your logic to the right place.

trigger AccountTrigger on Account (before insert, after update) { if (Trigger.isBefore && Trigger.isInsert) { // Logic for before insert } if (Trigger.isAfter && Trigger.isUpdate) { // Logic for after update } }

One thing that trips people up is forgetting that Trigger.new is a list. Even if you're only saving one record through the UI, Salesforce treats everything as a batch. Always, always write your code to handle a list of records.

Real-world example: auto-create a task

A common request: create a follow-up task when an Opportunity is marked "Closed Won". This is a classic "after update" scenario, because you want the Opportunity save to have succeeded before you start adding tasks.

trigger OpportunityTrigger on Opportunity (after update) { List tasksToCreate = new List();

for (Opportunity opp : Trigger.new) {
    // Check if the stage changed to Closed Won
    Opportunity oldOpp = Trigger.oldMap.get(opp.Id);
    
    if (opp.StageName == 'Closed Won' && oldOpp.StageName != 'Closed Won') {
        tasksToCreate.add(new Task(
            Subject = 'Onboarding Call',
            WhatId = opp.Id,
            Status = 'Not Started'
        ));
    }
}

if (!tasksToCreate.isEmpty()) {
    insert tasksToCreate;
}

}

Best practices for 2025

Most teams get this wrong by ignoring the basics. If you want your org to scale, you have to be disciplined. Here is the checklist I run on every project.

  1. One trigger per object. With several triggers on the same object you can't control the order they run in, and that is a recipe for bugs.
  2. Bulkify everything. Never put a SOQL query or a DML statement inside a loop. Use collections (Sets, Lists, Maps) to gather your data and process it all at once.
  3. Use a handler pattern. Move your logic into a separate class so it is easier to test and cleaner to read.
  4. Watch out for recursion. If your trigger updates the same record that fired it, you can end up in an infinite loop. Use a static variable or a framework to prevent that.
  5. Write meaningful tests. Coverage is just a number. Write tests that actually prove your logic works under different scenarios.

The handler pattern example

A handler is just a regular Apex class. Your trigger calls the class, the class does the work, and the trigger file stays thin.

public class AccountHandler { public void handleBeforeInsert(List newAccounts) { for (Account acc : newAccounts) { if (acc.Industry == null) { acc.Description = 'Please set an industry.'; } } } }

Preparing for interviews

If you're studying this cheat sheet for an upcoming job hunt, expect scenario-based questions: "How do you prevent a record from being deleted?" or "How do you handle a trigger that needs to call an external API?" These Apex Trigger Interview Questions are good practice.

If you need heavy processing that doesn't have to happen instantly, look at the asynchronous options. Processing 10,000 records in a synchronous trigger is asking for trouble. Use a Queueable or Batch job instead.

Key takeaways

  • Stick to one trigger per object to maintain control over execution order.
  • Use "before" triggers for same-record updates and "after" triggers for related record changes.
  • Never put SOQL or DML inside loops. Use collections.
  • Delegate your logic to a handler class to keep the trigger file clean.
  • Always check if field values actually changed using Trigger.oldMap before running logic.

Follow these patterns, keep this Apex Trigger Cheat Sheet handy, and your trigger code stays easy to maintain as your data volume grows. Go and check your current triggers now. Are any of them running SOQL in a loop?

Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment