If you are learning Salesforce development, one topic you simply cannot skip is Apex Triggers.
At first, triggers may look confusing.
You hear terms like:
- before insert
- after update
- Trigger.new
- Trigger.old
- bulkification
- governor limits
And suddenly everything feels complicated.
But here is the truth:
Apex Triggers are one of the most important parts of Salesforce development because they allow you to automate business logic directly inside Salesforce.
Once you understand the basics, triggers become much easier.
In this beginner-friendly guide, you will learn:
- What Apex Triggers are
- Why they are used
- Trigger syntax
- Before vs After triggers
- Trigger context variables
- Real Apex Trigger examples
- Trigger best practices
- Common mistakes beginners make
If you are completely new to Salesforce Apex, this tutorial will help you build a strong foundation.
What Is an Apex Trigger in Salesforce?
An Apex Trigger is Apex code that automatically runs before or after a record event happens in Salesforce.
These events include:
- Insert
- Update
- Delete
- Undelete
In simple words:
When a user creates, edits, or deletes a record, Salesforce can automatically execute custom logic using Apex Triggers.
For example:
- Automatically create a task when an Opportunity is closed
- Prevent users from deleting important records
- Update related records automatically
- Validate complex business rules
- Send data to external systems
Triggers help developers automate processes that are too complex for standard Salesforce tools.
If you are still learning Apex basics, first read our guide on SOQL Query Examples for Beginners in Salesforce and VS Code Setup for Salesforce Development before moving deeper into triggers.
Why Use Apex Triggers?
Many beginners ask:
“If Salesforce already has Flows and Validation Rules, why do we need triggers?”
Good question.
Salesforce Flows are powerful, but triggers are still important for:
Complex Business Logic
Some automation becomes too advanced for Flow.
Triggers give developers full coding flexibility.
Better Performance
For large data volumes, Apex Triggers are often faster and more scalable.
Cross-Object Automation
Triggers can easily update related objects.
External Integrations
Triggers can call APIs and integrate with external systems asynchronously.
Advanced Validations
Some business rules are impossible with normal validation rules.
Apex Trigger Syntax
A basic Apex Trigger looks like this:
trigger AccountTrigger on Account (before insert) {
for(Account acc : Trigger.new){
acc.Description = 'New Customer';
}
}
Let’s understand this:
| Part | Meaning |
|---|---|
| trigger | Keyword used to create trigger |
| AccountTrigger | Trigger name |
| on Account | Object name |
| before insert | Trigger event |
| Trigger.new | New records being inserted |
Types of Apex Triggers
There are two main trigger types in Salesforce.
Before Triggers
Before triggers run before the record is saved to the database.
They are mainly used for:
- Validation
- Updating same-record fields
- Data cleanup
Example:
trigger LeadBeforeTrigger on Lead (before insert) {
for(Lead ld : Trigger.new){
if(ld.LeadSource == null){
ld.LeadSource = 'Website';
}
}
}
This automatically sets Lead Source before saving the record.
After Triggers
After triggers run after the record is saved.
They are used when:
- You need Record Id
- Creating related records
- Updating other objects
- Sending notifications
Example:
trigger OpportunityAfterTrigger on Opportunity (after insert) {
List<Task> tasks = new List<Task>();
for(Opportunity opp : Trigger.new){
Task t = new Task(
Subject = 'Follow Up',
WhatId = opp.Id,
Status = 'Not Started'
);
tasks.add(t);
}
insert tasks;
}
This trigger creates a task automatically after Opportunity creation.
Apex Trigger Events
Salesforce supports multiple trigger events.
| Trigger Event | Description |
|---|---|
| before insert | Before record creation |
| before update | Before updating record |
| before delete | Before deleting record |
| after insert | After record creation |
| after update | After updating record |
| after delete | After deleting record |
| after undelete | After restoring deleted record |
You can combine multiple events inside one trigger.
Example:
trigger AccountTrigger on Account (
before insert,
before update,
after delete
) {
}
Trigger Context Variables in Salesforce
Trigger context variables are extremely important.
These variables help you access records inside triggers.
Trigger.new
Contains new versions of records.
Available in:
- insert
- update
- undelete
Example:
for(Account acc : Trigger.new){
System.debug(acc.Name);
}
Trigger.old
Contains old record values.
Available in:
- update
- delete
Example:
for(Account oldAcc : Trigger.old){
System.debug(oldAcc.Name);
}
Trigger.newMap
Map of new records by Id.
Account acc = Trigger.newMap.get(accountId);
Trigger.oldMap
Map of old records by Id.
Very useful for comparing values.
Account oldAcc = Trigger.oldMap.get(acc.Id);
Trigger.isInsert
Returns true if trigger fired because of insert.
if(Trigger.isInsert){
}
Trigger.isUpdate
Returns true during update.
Trigger.isDelete
Returns true during delete operation.
Trigger.isBefore
Returns true for before triggers.
Trigger.isAfter
Returns true for after triggers.
Real Apex Trigger Example for Beginners
Now let’s create a simple real-world trigger.
Requirement
Whenever a new Account is created:
- Automatically set Rating = Hot if Annual Revenue > 1 Million
Trigger Example
trigger AccountRatingTrigger on Account (before insert, before update) {
for(Account acc : Trigger.new){
if(acc.AnnualRevenue != null &&
acc.AnnualRevenue > 1000000){
acc.Rating = 'Hot';
}
}
}
This is a very common beginner-level Salesforce Apex Trigger example.
Before Trigger vs After Trigger
This is one of the most asked Salesforce interview questions.
| Before Trigger | After Trigger |
|---|---|
| Runs before save | Runs after save |
| Faster | Slightly slower |
| Can modify same record | Cannot modify same record directly |
| No DML required | DML often required |
| Used for validation | Used for related records |
Simple rule:
- Use before triggers for same-record updates
- Use after triggers for related object operations
Bulkification in Apex Triggers
This is extremely important.
Salesforce processes records in batches.
A trigger should always work for:
- 1 record
- 10 records
- 200 records
Bad example:
for(Account acc : Trigger.new){
insert new Task(Subject='Follow Up');
}
This causes governor limit problems.
Correct approach:
List<Task> tasks = new List<Task>();
for(Account acc : Trigger.new){
tasks.add(
new Task(Subject='Follow Up')
);
}
insert tasks;
This is called bulkification.
Governor Limits and Triggers
Salesforce has governor limits to protect system performance.
Common limits:
| Limit | Value |
|---|---|
| SOQL Queries | 100 |
| DML Statements | 150 |
| CPU Time | 10 Seconds |
| Records Per Batch | 200 |
That is why developers must write optimized triggers.
Common Mistakes Beginners Make
SOQL Inside Loops
Wrong:
for(Account acc : Trigger.new){
Contact c = [
SELECT Id FROM Contact
LIMIT 1
];
}
This hits SOQL limits quickly.
DML Inside Loops
Wrong:
for(Account acc : Trigger.new){
insert new Task();
}
Always use collections.
Multiple Triggers on Same Object
Best practice:
Use one trigger per object.
Ignoring Null Checks
Always validate null values properly.
Trigger Best Practices
Here are important Salesforce trigger best practices.
Use One Trigger Per Object
Cleaner architecture.
Use Trigger Handler Pattern
Move logic into Apex classes.
Bulkify Everything
Always assume 200 records.
Avoid Hardcoded IDs
Use Custom Metadata or RecordType queries.
Write Test Classes
Minimum 75% code coverage required.
Use Collections
Use:
- List
- Set
- Map
for optimized performance.
Trigger Handler Pattern (Recommended)
Instead of writing everything inside trigger:
trigger AccountTrigger on Account (before insert) {
}
Use:
trigger AccountTrigger on Account (before insert) {
AccountTriggerHandler.beforeInsert(Trigger.new);
}
This makes code:
- cleaner
- reusable
- scalable
- easier to test
When Should You Use Flow Instead of Trigger?
In modern Salesforce development:
Use Flow for:
- simple automation
- approvals
- notifications
- screen processes
Use Apex Trigger for:
- complex logic
- high-volume operations
- integrations
- advanced validations
Knowing when to use Flow vs Trigger is an important developer skill.
How to Test Apex Triggers
Salesforce requires test classes.
Example:
@isTest
public class AccountTriggerTest {
@isTest
static void testTrigger(){
Account acc = new Account(
Name = 'Test Account',
AnnualRevenue = 2000000
);
insert acc;
Account insertedAcc = [
SELECT Rating
FROM Account
WHERE Id = :acc.Id
];
System.assertEquals(
'Hot',
insertedAcc.Rating
);
}
}
Testing is mandatory for Salesforce deployment.
Final Thoughts
Apex Triggers are one of the core foundations of Salesforce development.
At first, they may feel difficult.
But once you understand:
- trigger events
- context variables
- before vs after logic
- bulkification
everything starts making sense.
The best way to learn triggers is by practicing real examples inside your Salesforce Developer Org.
Start with simple automation first.
Then slowly move toward:
- trigger handlers
- asynchronous Apex
- integrations
- enterprise architecture
That is how strong Salesforce developers are built.
you can also leran this topics :
SOQL Query Examples for Beginners in Salesforce
Salesforce Inspector Chrome Extension Guide for Beginners
VS Code Setup for Salesforce Development
Salesforce CLI Installation and Setup Guide
Salesforce Flow Tutorial for Beginners: Complete Step-by-Step Guide (2026)
Salesforce Certification Guide: Which One Should You Get First? (2026)