Skip to main content

SF-0326 · Coding · Easy

Can you write trigger syntax and an example?

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

The Apex trigger syntax is short and rigid. The shape never changes — only the object, the events, and the body do.

The grammar

trigger TriggerName on ObjectAPIName (
    before insert, before update, before delete,
    after insert, after update, after delete, after undelete
) {
    // body
}

Three parts:

  1. trigger TriggerName — a unique name in the org. Convention: <Object>Trigger, e.g. AccountTrigger.
  2. on ObjectAPIName — the SObject this trigger fires on. One trigger fires on exactly one object.
  3. (events) — one or more of seven combinations: before insert, before update, before delete, after insert, after update, after delete, after undelete. (before undelete doesn’t exist — there’s nothing to validate before a restore.)

A minimal example

A before-insert trigger that defaults the Rating__c field to 'Warm' if the user didn’t supply one.

trigger AccountDefaultRating on Account (before insert) {
    for (Account a : Trigger.new) {
        if (a.Rating == null) {
            a.Rating = 'Warm';
        }
    }
}

A few things to notice:

  • We don’t update the records — we mutate them. In a before trigger, Trigger.new is the in-memory copy that’s about to be saved. Mutate it; the save uses your changes.
  • for (Account a : Trigger.new) works because Trigger.new is strongly typed to the object the trigger is declared on.
  • No SOQL, no DML — the whole thing runs on what’s already in memory.

A more realistic example — Account → Contact roll-up

When a contact is inserted or deleted, recompute Total_Contacts__c on the parent account.

trigger ContactCountOnAccount on Contact (after insert, after delete) {

    Set<Id> accountIds = new Set<Id>();

    if (Trigger.isInsert) {
        for (Contact c : Trigger.new) {
            if (c.AccountId != null) accountIds.add(c.AccountId);
        }
    } else { // delete
        for (Contact c : Trigger.old) {
            if (c.AccountId != null) accountIds.add(c.AccountId);
        }
    }

    if (accountIds.isEmpty()) return;

    // One aggregate query covers all parents
    Map<Id, Integer> countByAccount = new Map<Id, Integer>();
    for (AggregateResult ar : [
        SELECT AccountId acc, COUNT(Id) cnt
        FROM Contact
        WHERE AccountId IN :accountIds
        GROUP BY AccountId
    ]) {
        countByAccount.put((Id) ar.get('acc'), (Integer) ar.get('cnt'));
    }

    // Build the parent updates
    List<Account> toUpdate = new List<Account>();
    for (Id aId : accountIds) {
        toUpdate.add(new Account(
            Id = aId,
            Total_Contacts__c = countByAccount.containsKey(aId) ? countByAccount.get(aId) : 0
        ));
    }
    update toUpdate;
}

This single trigger shows the patterns interviewers look for:

  • Bulk-safe — Set/Map, no SOQL/DML in a loop.
  • Context-aware — checks Trigger.isInsert to decide whether to read Trigger.new or Trigger.old.
  • Aggregate query — pushes counting to the database instead of looping in Apex.

What lives where: Trigger.new vs Trigger.old

VariableTypeAvailable in…
Trigger.newList<SObject>All insert/update events; null in delete
Trigger.newMapMap<Id, SObject>After-insert (Ids exist), all update events
Trigger.oldList<SObject>Update and delete events
Trigger.oldMapMap<Id, SObject>Update and delete events

Production shape — delegate to a handler

In real projects, the trigger file itself contains exactly one line per event. All logic lives in a handler class for testability and the one trigger per object rule.

trigger AccountTrigger on Account (
    before insert, before update, before delete,
    after insert, after update, after delete, after undelete
) {
    new AccountTriggerHandler().run();
}

What interviewers are really looking for

A junior writes the syntax and a one-line example. A mid-level developer writes a bulk-safe rollup with Set<Id>, no SOQL in loops, and the Trigger.isInsert branch. A senior delegates to a handler class with a recursion guard and a bypass switch. Show the third tier — even briefly — and you’ve moved out of the “remembers Apex” bucket into the “writes Apex for production” bucket.

Verified against: Apex Developer Guide — Triggers. Last reviewed 2026-05-17.