Salesforce Triggers: A Complete Guide

If you’re stepping into your Salesforce Developer journey, learning Salesforce Apex Triggers is one of the most important steps to become a confident Salesforce developer. Apex Triggers automate actions behind the scenes when data changes in Salesforce.

What is an Apex Trigger

An Apex Trigger in Salesforce is a piece of Apex code that runs automatically whenever a specific action happens in the database. such as inserting, updating, or deleting a record. Apex Trigger is a smart “reaction system” that gets initiated when something happens in Salesforce. Apex Trigger immediately responds without anyone needing to click a button. Apex Triggers help automate important background tasks, ensure data consistency, and handle logic that must execute the moment data changes.

Definition:
“Apex Trigger is a piece of Apex code that executes before or after a DML (Data Manipulation Language) operation occurs on a record.”

A Simple Real Life Story For Beginners

Imagine Nina, the lively owner of CoffeeBuzz, a crowded little café famous for its smooth Cappuccino. To delight her loyal customers, Nina decided that every time someone ordered a Cappuccino, they should instantly receive a 50% off coupon for their next visit. She tried doing this manually, but as orders jumped from 10 to 50 to 200 a day, she started missing people, and the customer experience became inconsistent. That’s when she needed a helper who never forgets, never makes mistakes, and works behind the scenes every single time. That helper is a Salesforce Apex Trigger. It behaves like an automated smart assistant that acts the moment a specific event occurs. In Nina’s case, it means: “Whenever a new Cappuccino order is created, automatically generate a coupon.” In simple terms: Trigger = When someone orders a Cappuccino, Salesforce automatically creates a coupon.

When to Use Salesforce Apex Triggers

Apex Triggers are a powerful feature in Salesforce that allow developers to execute custom logic automatically when records are inserted, updated, deleted, or undeleted. However, triggers should not be the first choice for every requirement. Salesforce recommends using declarative tools like Flow whenever possible and switching to Apex Triggers only when necessary.

You Should Use Apex Triggers When Point-And-Click Tools Are Not Enough

Apex Triggers should be used when business requirements cannot be fulfilled using point-and-click tools such as Flows or Validation Rules. When the logic becomes too complex or requires advanced control over data processing, triggers provide the required flexibility.

Real-Time Scenarios Where Apex Triggers Are Required

  • Complex data validations across multiple objects
  • Creation of related records during data processing
  • Updates to child records when parent data changes
  • Backend calculations executed in real time

But remember: If something can be done using Flows or Validation Rules, prefer them first. (Salesforce best practice: “Clicks before Code.”)

Types of Apex Triggers in Salesforce

There are two main types of triggers:

1. Before Trigger

Runs before the record is saved to the database.

Use Case:

  • Validate or modify field values before saving.
  • Ensure data is correct before storing.

Example: Set a default Status = “Active” before saving a new record.

2. After Trigger

Runs after the record is saved to the database.

Use Case:

  • Access system fields like Record ID, CreatedDate, etc.
  • Create related records after the main record is inserted
  • Send emails or make callouts.

Example: After creating a new Order, automatically create an Invoice record.

Apex Trigger Events in Salesforce

There are 7 main Apex trigger events, and they are linked to DML (Data Manipulation Language) actions like insert, update, delete, and undelete. Let’s see them one by one.

  1. Before Insert :
    When it happens : Before a new record is saved in the database.
    Use case : To check or modify data before saving it.
    Coffee Example : Before saving a new coffee order, you want to check whether the customer’s phone number is filled in.
    if not, throw an error — “Please enter your contact number!”
  2. After Insert :
    When it happens : After the record is successfully saved in the database.
    Use case : When you need the record ID or want to create related records.
    Coffee Example : After saving a new coffee order, send a “Thank You” email or SMS to the customer for their purchase.
  3. Before Update :
    When it happens : Before an existing record is updated.
    Use case : Validate data before making changes.
    Coffee Example : Before updating an order’s status to Delivered, make sure the payment status is Paid. If not, stop the update.
  4. After Update :
    When it happens : After a record is updated.
    Use case : Update related records or log history.
    Coffee Example : After updating the order status to Delivered, update the customer’s total purchase count and loyalty points.
  5. Before Delete :
    When it happens : Before a record is deleted.
    Use case : Check conditions before allowing delete.
    Coffee Example : Before deleting an order, check if it’s already paid. If yes, stop the deletion — because you don’t want to delete paid orders!
  6. After Delete :
    When it happens : After a record is deleted.
    Use case : Clean up related records or send alerts.
    Coffee Example : After deleting a coffee order, remove the record from the loyalty tracking system.
  7. After Undelete :
    When it happens: After a record is restored from the Recycle Bin.
    Use case : Restore or reconnect related data.
    Coffee Example : If a coffee order was accidentally deleted and then undeleted, restore the customer’s loyalty points for that order.

Salesforce Apex Trigger Event Summary Table

EventWhen it happensCommon Use CaseCoffee Shop Example
Before InsertBefore record savedValidate dataCheck if the customer’s phone is filled
After InsertAfter record savedSend emails, create related recordsSend “Thank You” message
Before UpdateBefore record updatedValidate changesEnsure payment before marking delivered
After UpdateAfter record updatedUpdate related dataUpdate loyalty points
Before DeleteBefore record deletedStop invalid deleteBlock deletion of paid orders
After DeleteAfter record deletedClean related recordsRemove order from loyalty list
After UndeleteAfter record restoredReconnect related data

When to Choose “Before” and “After” Trigger

Before Event TriggerAfter Event Trigger
Used when working with the same object recordsUsed when updating other object records (two objects involved)
Used to validate records or set field values before savingUsed to perform post-save actions like sending emails or making callouts
No DML is requiredDML is required
Useful for validation logic, setting default values, or modifying the same recordUseful for updating related/non-related records, logging data, or accessing system fields
Runs before the record is saved to the databaseRuns after the record is saved to the database
Example: Validate phone format before inserting a recordExample: Create a task after an Opportunity is closed won
Best for: Data validation and field updates on same objectBest for: Email alerts, callouts, related record updates

Apex Trigger Syntax in Salesforce

 Trigger TriggerName on ObjectName (trigger_events) {
// Your logic here
}

Parts of the Syntax :

PartMeaning / Description
triggerKeyword used to define a trigger
TriggerNameName of the trigger (developer-defined)
onKeyword that connects the trigger to an object
ObjectNameThe Salesforce object on which the trigger runs (e.g., Account, Contact, Lead)
trigger_eventsEvents that cause the trigger to fire (e.g., before insert, after update, etc.)

Common Trigger Events:

Before EventsAfter Events
before insertafter insert
before updateafter update
before deleteafter delete
(no before undelete)after undelete

Example Trigger :

trigger AccountTrigger on Account (before insert, before update, after insert, after update) {
System.debug('Trigger fired');
}

Salesforce Apex Trigger Context Variables

When working with Apex Triggers in Salesforce, you’ll often need to understand which records are being processed and what action caused the trigger to run.
That’s where Trigger Context Variables come in!
They are special variables provided by Salesforce that tell you everything about what’s happening in the trigger — like whether the trigger was fired by an insert, update, or delete, and which records are involved.

What Are Apex Trigger Context Variables?

Think of context variables as helpers that Salesforce automatically gives you inside every trigger.
They help you know below points :

  • What operation is happening (Insert, Update, Delete)
  • Whether it’s before or after the trigger
  • Which records are new or old

List of Apex Trigger Context Variables :

Variable NameTypeDescription
Trigger.newList
Contains new versions of records being inserted or updated. Editable only in before triggers.
Trigger.oldListContains old versions of records before update or delete.
Trigger.newMapMapMap of new records with Ids. Used to compare new vs old values.
Trigger.oldMapMapMap of old records with Ids. Used in update and delete triggers.
Trigger.operationTypeenum Returns an enum of type System.TriggerOperation representing the current trigger operation. Possible values are: BEFORE_INSERT, BEFORE_UPDATE, BEFORE_DELETE, AFTER_INSERT, AFTER_UPDATE, AFTER_DELETE, AFTER_UNDELETE. This is useful when handling multiple trigger events in a single trigger using a switch statement.
Trigger.sizeIntegerNumber of records processed in the current trigger execution (max 200).

When We Use apex trigger – Context Variables

DML OperationBefore TriggerAfter TriggerExample Use Case
InsertTrigger.newTrigger.new, Trigger.newMapValidate new records before saving, or send a welcome email after insertion.
UpdateTrigger.new, Trigger.old, Trigger.newMap, Trigger.oldMapTrigger.new, Trigger.old, Trigger.newMap, Trigger.oldMapCompare old and new values to detect changes and perform updates accordingly.
DeleteTrigger.old, Trigger.oldMapTrigger.old, Trigger.oldMapLog deleted records or update related child records.
Undelete(Nothing)Trigger.new, Trigger.newMapRestore related data when a record is undeleted.

Key Takeaways :

  • Use Trigger.new and Trigger.old to access record data.
  • Use Trigger.newMap and Trigger.oldMap when you need to look up by ID.
  • Trigger.size helps handle bulk operations safely.

Simple Real-Life Example :
Imagine Salesforce as a school register system:

  • When a new student joins → isInsert
  • When a student’s info changes → isUpdate
  • When a student leaves → isDelete
  • Before saving student details → isBefore
  • After saving → isAfter
  • Trigger.new = “list of current student details”
  • Trigger.old = “list of previous student details”

Basic Apex Trigger to Check Context (All 7 Events) :

trigger AccountTrigger on Account (before insert, before update, before delete,after insert, after update, after delete,
                                                           after undelete) {
if (Trigger.isInsert) {
System.debug('isInsert Output');
}
if (Trigger.isUpdate) {
    System.debug('isUpdate Output');
}

if (Trigger.isDelete) {
    System.debug('isDelete Output');
}

if (Trigger.isUndelete) {
    System.debug('isUnDelete Output');
}
}

Let’s Understand This: When you run this trigger on the Account object

  • Case 1: Creating a New Account
    creation of a new record (Insert operation):
    • Trigger.isInsert = True
    • Output: “isInsert Output”
    • It will print 2 times
      • Once before insert
      • Once after insert
    • Think like this: “I’m saving a new account. Before saving, trigger checks it; after saving, trigger confirms it.”
      So total output = 2 times(Before Insert + After Insert)
  • Case 2: Updating an Account
    updating an existing record:
    • Trigger.isUpdate = True
    • Output: “isUpdate Output”
    • It will print 2 times
      • Once before update
      • Once after update
    • Think like this: “Before updating, trigger checks the old and new values. After updating, trigger confirms changes.”
      So total output = 2 times(Before Update + After Update)
  • Case 3: Deleting an Account
    deleting a record:
    • Trigger.isDelete = True
    • Output will happen 2 times
      • Once before delete
      • Once after delete
    • Think like this : “Before deleting, trigger says goodbye and after deleting, it confirms the record is gone.”
      So total output = 2 times (Before Delete + After Delete)
  • Case 4: Undelete (Restore)
    When you undelete a record (bring it back from the Recycle Bin)
    • Trigger.isUndelete = True
    • It runs only once
      • Only in after undelete
    • Think like this: “The Record was gone. Now I’m bringing it back — trigger runs once to confirm it’s restored.”
      So total output = 1 time(Only After Undelete — no before undelete)

Summary Table

OperationContext VariableTrigger RunsWhen It Runs
InsertTrigger.isInsert2 timesBefore Insert + After Insert
UpdateTrigger.isUpdate2 timesBefore Update + After Update
DeleteTrigger.isDelete2 timesBefore Delete + After Delete
UndeleteTrigger.isUndelete1 timeAfter Undelete only

Context variables tell your trigger :
“Hey, what’s happening now — creating, updating, deleting, or restoring?”
They help your trigger know what to do and when to do it.
If you understand these four —isInsert, isUpdate, isDelete, isUndelete — you already know 70% of trigger basics!

Salesforce Triggers Using Real-Time Example

trigger accountTrigger on Account (before insert, before update, before delete,
    after insert, after update, after delete, after undelete
) {

    /* BEFORE INSERT – validate before saving */
    if (Trigger.isBefore && Trigger.isInsert) {
        for (Account acc : Trigger.new) {
            if (acc.Rating == null) {
                acc.addError('Rating is required');
            }
        }
    }

    /* AFTER INSERT – confirmation */
    if (Trigger.isAfter && Trigger.isInsert) {
        System.debug('Account created successfully');
    }

    /* BEFORE UPDATE – control changes */
    if (Trigger.isBefore && Trigger.isUpdate) {
        for (Account acc : Trigger.new) {
            acc.Description = 'Account updated';
        }
    }

    /* AFTER UPDATE – post update action */
    if (Trigger.isAfter && Trigger.isUpdate) {
        System.debug('Account updated successfully');
    }

    /* BEFORE DELETE – security check */
    if (Trigger.isBefore && Trigger.isDelete) {
        for (Account acc : Trigger.old) {
            if (acc.Type == 'Customer - Direct') {
                acc.addError( 'Customer - DirectType cannot be deleted');
            }
        }
    }

    /* AFTER DELETE – audit */
    if (Trigger.isAfter && Trigger.isDelete) {
        System.debug('Account deleted');
    }

    /* AFTER UNDELETE – recovery */
    if (Trigger.isAfter && Trigger.isUndelete) {
        System.debug('Account restored from Recycle Bin');
    }
}

Understanding All 7 Salesforce Trigger Events with One Real-Time Example

1: Before Insert

User creates a new Account
Real-time meaning:
Before saving, the system checks whether the data is correct.
Example: Rating field
“Rating field must not be empty while creating an Account.”

2: After Insert

Account is saved successfully.
Real-time meaning: Now the record exists in the database.
Example: Send notification
“After the account is created, Salesforce performs post-save actions.”

3: Before Update

User edits the same Account
Real-time meaning: Before updating, Salesforce controls what is allowed to change.
Example: Validate updated data
“Before updating the account, Salesforce checks if the changes are allowed.”

4: After Update

Account updated successfully
Real-time meaning: Changes are committed to the database.
Example: Sync related records
“After updating, Salesforce performs follow-up operations.”

5: Before Delete

User tries to delete the Account
Real-time meaning: Salesforce checks whether deletion is allowed.
Example: Block deletion of important customers
“Before deleting, Salesforce verifies business rules.”

6: After Delete

Account deleted
Real-time meaning: The Record is removed from active data.
Example: Cleanup related data
“After deletion, Salesforce records the action for tracking.”

7: After Undelete

Account restored from the Recycle Bin
Real-time meaning: The account is brought back.
Example: Restore related data
“After undelete, Salesforce handles recovery actions.”

Understanding Trigger.isBefore and Trigger.isAfter in Salesforce Apex Triggers

trigger AccountTrigger on Account (before insert, before update, before delete,after insert, after update, after delete,
                                   after undelete) {
if (Trigger.isBefore) {
System.debug('isBefore Output');
}
if (Trigger.isAfter) {
    System.debug('isAfter Output');
}

}

1. Trigger.isBefore

This means: “I want to do something before Salesforce saves the record to the database.”
Example :

  • Set default field values
  • Validate data
  • Modify field values

When will it run?

  • Before Insert
  • Before Update
  • Before Delete

Output : Only one output comes each time — depending on what you are doing (insert, update, or delete).
Example thought : “Before saving this Account, I’ll make sure the Account Name is not empty.”

2. Trigger.isAfter

This means : “I want to do something after Salesforce has saved the record.”
Example:

  • Send an email notification
  • Create related records
  • Call external systems

When will it run?

  • After Insert
  • After Update
  • After Delete
  • After Undelete

Output : It will trigger after Salesforce has successfully saved or restored the record.

Example thought : “The Account is now saved, so I’ll send a thank-you email.”

Small Tip : isBefore is mostly used to change or validate data
isAfter is used when you need record Ids or related actions

Final Takeaway : Trigger.isBefore → Change or check data before saving
Trigger.isAfter → Do something after saving (like send an email or create a related record)

Once you understand these two, you’ve mastered when to make your trigger act!

Understanding Trigger.isBefore and Trigger.isInsert Together in Salesforce Apex Triggers

In Salesforce, when we work with triggers, we often use context variables to control when our trigger should run.
Two of the most common ones are:

  • Trigger.isBefore → Runs before a record is saved.
  • Trigger.isInsert → Runs when a record is being inserted (created).

But what happens when we use both together in a condition?
Example:

trigger AccountTrigger on Account (before insert, before update, before delete,after insert, after update, after delete
                                                                                                      , after undelete) {
if (Trigger.isBefore && Trigger.isInsert) {
System.debug('Before Insert Output');
}
}

What’s Happening Here?
Let’s decode this line step by step

if (Trigger.isBefore && Trigger.isInsert)
  • Trigger.isBefore → means before the record is saved
  • Trigger.isInsert → means while inserting a new record
  • && → means AND condition (both must be true)

this trigger says:
“Only run this code when we are inserting a new record and it’s happening before saving.”
Output Explanation : When you create a new Account record,

  • The trigger runs in two stages — Before Insert and After Insert.
  • But since we used Trigger.isBefore && Trigger.isInsert,
    it runs only once — during the Before Insert stage.

Output:
Before Insert Output (only one time)
Why Only One Output?
Because we told Salesforce:
“Run this only when it’s both before and insert.”
That condition is true only for Before Insert event.Not for After Insert or any other event.

ConditionMeaningWhen It RunsOutput Count
Trigger.isBeforeRuns before any DML (insert, update, delete)Before Insert / Before Update / Before DeleteOne output for whichever operation happens
Trigger.isInsertRuns when record is being insertedBefore Insert & After InsertTwo outputs (one before, one after)
Trigger.isBefore && Trigger.isInsertRuns only before the record is insertedOnly Before InsertOne output

In Salesforce triggers:

  • isBefore means “before saving”
  • isInsert means “creating a new record”
  • Combining them (isBefore && isInsert) means “before creating a new record”

That’s how you make your trigger more specific and efficient!

How Trigger.isBefore, Trigger.isInsert and Trigger.isUpdate Work Together in Salesforce Apex Triggers:

When working with Salesforce Triggers, it’s important to know when and why your trigger runs.
Sometimes, you want your trigger to behave differently when :

  • A new record is created (Insert)
  • An existing record is updated (Update)

In this post, we’ll see how to separate logic for insert and update inside a before trigger — in the simplest way.
Example:

trigger AccountTrigger on Account (before insert, before update, before delete,after insert, after update, after delete 
                                                                                                   , after undelete) {
if (Trigger.isBefore) {

if (Trigger.isInsert) {
System.debug('Before Insert Output Result');
}
else{
 if (Trigger.isUpdate) {
System.debug('Before Update Output Result');
}
}
}
}

Step-by-Step Explanation :

Trigger.isBefore

  • Meaning: Run this block before Salesforce writes the record to the database.
  • Events covered in this block: Before Insert, Before Update, Before Delete.
  • If the current event is not one of those, the if (Trigger.isBefore) block is skipped entirely.

Inside if (Trigger.isBefore) — check the specific event

  • if (Trigger.isInsert)
    • Means: Are we creating new records?
    • When true: run code for Before Insert (e.g, System.debug('Before Insert Output Result');).
  • else if (Trigger.isUpdate)
    • Means: Are we modifying existing records?
    • When true: run code for Before Update (e.g., System.debug('Before Update Output Result');).
  • (You can also check else if (Trigger.isDelete) inside the isBefore block for Before Delete.)

Important: do not re-check Trigger.isInsert inside the isUpdate branch
Your earlier explanation repeated If (Trigger.isInsert) while already inside the isUpdate path — that is logically impossible and redundant. Use else if (or separate if checks) to check distinct events.

Output:
When You Create a New Record:

  • Trigger.isBefore → True
  • Trigger.isInsert → True
    Output → “Before Insert Output Result”

When You Update an Existing Record:

  • Trigger.isBefore → True
  • Trigger.isUpdate → True
    Output → “Before Update Output Result”

So What’s Happening Behind the Scenes?
Salesforce checks:

  • Is the trigger running before the record is saved?
  • If yes, then — is it a new record (insert) or an existing one (update)?

Depending on the answer, the correct message runs in System.debug.
Tip: Always use if and else-if blocks in your triggers to handle different DML operations separately.
it makes your trigger cleaner, faster, and easier to debug.
Example:

  • One section for insert
  • One for update
  • One for delete (if needed)

Final Takeaway:
When your trigger runs before the record is saved:

  • Use Trigger.isInsert for new record logic
  • Use Trigger.isUpdate for existing record logic
  • Both are under Trigger.isBefore so they happen before saving changes to the database.

That’s how you control exactly when and what your trigger does — just like a smart teacher guiding both new and old students!

Understanding isBefore vs isAfter in Salesforce Apex Triggers:

Example:

trigger AccountTrigger on Account (before insert, before update, before delete, 
                                   after insert, after update, after delete, after undelete) {
// Check BEFORE operations
if (Trigger.isBefore) {
    if (Trigger.isInsert) {
        System.debug('Before Insert Output Result');
    }
    else if (Trigger.isUpdate) {
        System.debug('Before Update Output Result');
    }
    else {
        System.debug('Before Delete Output Result');
    }
}

// Check AFTER operations
else {
    if (Trigger.isInsert) {
        System.debug('After Insert Output Result');
    }
    else if (Trigger.isUpdate) {
        System.debug('After Update Output Result');
    }
    else if (Trigger.isDelete) {
        System.debug('After Delete Output Result');
    }
    else {
        System.debug('After Undelete Output Result');
    }
  }
}

Understanding the Code:

  • Trigger name: AccountTrigger
  • Object: Account
  • Events: before insert, before update, before delete, after insert, after update, after delete, after undelete
    Total 7 events

What Happens Here:

  • The trigger checks two main parts:
    Before part – Runs before saving the record.
    After part – Runs after saving the record.
  • Inside each part, it checks which DML operation happened:
    • Insert → A new record was created.
    • Update → A record was changed.
    • Delete → A record was removed.
    • Undelete → A deleted record was restored.

Output (in Debug Log) :

Action PerformedTrigger PartDebug Output Message
Creating new recordBefore InsertBefore Insert Output Result
Record saved successfullyAfter InsertAfter Insert Output Result
Updating existing recordBefore Update / After UpdateBefore Update Output Result / After Update Output Result
Deleting recordBefore Delete / After DeleteBefore Delete Output Result / After Delete Output Result
Restoring deleted recordAfter UndeleteAfter Undelete Output Result

‘Specific Context Variables’ will see with example how it works:

Trigger.new
Trigger.newMap
Trigger.old
Trigger.oldMap

It holds all record values. These are special variables used inside triggers to access record data.

Example:


trigger AccountTrigger on Account (before insert, before update, before delete,after insert, after update, after delete,
                                        after undelete) {

if (Trigger.isBefore) {
    if (Trigger.isInsert) {
        System.debug('Before Insert Output Result ' + Trigger.new );
        System.debug('Before Insert Output Result ' +  Trigger.old);
    }
    else if (Trigger.isUpdate) {
        System.debug('Before Update Output Result ' + Trigger.new );
        System.debug('Before Insert Output Result ' +  Trigger.old);
    }
    else {
        System.debug('Delete Output Result ' + Trigger.new );
        System.debug('Before Insert Output Result ' +  Trigger.old);
    }
  }
}

Explanation :

  • When we create a new record:
    • Check the Debug Log in Developer Console.
    • You will see → Id = null
    • Because the record is not yet saved to the database.
    • Whatever field values you entered will show, but Id remains null (before saving).
  • When we update the same record:
    • Check again in Debug Log.
    • Now Id will come because record is already created.
    • You can see old values (before update) and new values (after update).
  • When we delete a record:
    • Check again → Id will come.
    • Because the record existed before deleting.
    • Trigger.old has data because record existed earlier.
    • But while deleting, the record is being removed from the database.

Note:

  • Trigger.new → Supports Before Insert and Before Update
  • Trigger.old → Supports Before Update and Before Delete

Example Lists:

List<Account> accListNew = Trigger.new;
List<Account> accListOld = Trigger.old;

accListNew → holds new record values
accListOld → holds old record values

Related Resources

Conclusion

Apex Triggers are used when business requirements cannot be handled using declarative tools like Flows or Validation Rules. They help automate complex logic during data changes and ensure data accuracy and consistency. However, triggers should always follow Salesforce’s Clicks Before Code best practice. When designed properly, Apex Triggers become a powerful and efficient solution rather than a complex one.

Deepa Sangeetham
Deepa Sangeetham
Articles: 2

Leave a Reply

Your email address will not be published. Required fields are marked *