20 Real Apex & Triggers Salesforce Interview Questions & Answers (2026) – Asked in Accenture, Deloitte, TCS, Capgemini, Infosys, EY & More

Published On: August 7, 2026

Salesforce Apex & Triggers Interview Guide (2026)


1. Explain the Salesforce Order of Execution with a Real-World Example.

Definition

The Salesforce Order of Execution (OOE) is the sequence of events Salesforce follows whenever a record is inserted, updated, deleted, or undeleted. It determines which automation runs first and which runs later.

Understanding the Order of Execution is one of the most frequently asked Salesforce Developer interview topics because multiple automations (Validation Rules, Flows, Apex Triggers, Assignment Rules, Roll-up Summaries, etc.) may execute on a single transaction.


How It Works

When a user clicks Save, Salesforce processes the record in a predefined sequence.

Simplified Order of Execution

User Saves Record
        │
        ▼
System Validation
        │
        ▼
Before Record-Triggered Flow
        │
        ▼
Before Trigger
        │
        ▼
Validation Rules
        │
        ▼
Duplicate Rules
        │
        ▼
Save Record (Not Committed Yet)
        │
        ▼
After Trigger
        │
        ▼
Assignment Rules
        │
        ▼
Auto Response Rules
        │
        ▼
Workflow Rules
        │
        ▼
Workflow Field Updates
        │
        ▼
(Triggers run again if Workflow updated fields)
        │
        ▼
Processes / Process Builder (Legacy)
        │
        ▼
After-save Flow
        │
        ▼
Escalation Rules
        │
        ▼
Roll-Up Summary Calculation
        │
        ▼
Criteria-Based Sharing
        │
        ▼
Commit Transaction
        │
        ▼
Post Commit Logic
(Email, Future, Queueable, Platform Events)

Real-Time Example

Imagine an Opportunity is updated.

Company Requirement:

  • Sales Rep changes Stage = Closed Won
  • Validation Rule checks Amount > 0
  • Before Trigger calculates Commission
  • After Trigger creates Project
  • Flow sends Welcome Email
  • Future Method calls ERP API

Execution:

User Updates Opportunity

↓

Validation

↓

Before Flow

↓

Before Trigger
Calculate Commission

↓

Validation Rule
Amount > 0

↓

Record Saved

↓

After Trigger
Create Project

↓

After-save Flow
Send Email

↓

Commit

↓

Future Method
Call ERP API

Everything happens in this exact order.


Why Is It Important?

Suppose:

Flow updates a field.

Trigger also updates the same field.

Workflow updates another field.

You might accidentally execute the trigger twice, causing:

  • Duplicate Tasks
  • Duplicate Emails
  • Duplicate Opportunities
  • CPU Time Errors

This is why understanding the execution order helps prevent unexpected behavior.


Interview Scenario

Interviewer:

Why did my trigger execute twice?

Answer:

Because Workflow Field Updates (or certain automation) modify the record after the initial save, Salesforce performs another update within the same transaction, causing the before and after triggers to run again. That’s why recursion prevention is essential.


Best Practices

  • Know the complete Order of Execution.
  • Keep business logic in one automation tool when possible.
  • Avoid mixing Flow, Workflow, Process Builder, and Apex for the same object.
  • Use Trigger Handlers instead of writing logic directly in triggers.
  • Prevent recursion.

Governor Limits / Performance

Poor understanding of the execution order can cause:

  • Too many SOQL queries (101)
  • Too many DML statements (151)
  • CPU Time Limit Exceeded
  • Duplicate automation
  • Infinite trigger recursion

2. How Do You Prevent Recursion in Apex Triggers?

Definition

Recursion occurs when a trigger updates the same object again, causing itself to execute repeatedly until Salesforce stops the transaction.

This commonly happens when:

  • Trigger updates the same record.
  • Flow updates the record.
  • Workflow updates fields.
  • Process Builder performs another update.

Problem Example

Account Trigger

↓

Update Account

↓

Trigger Fires Again

↓

Update Again

↓

Trigger Fires Again

↓

CPU Time Exceeded

Solution 1: Static Boolean (Simple)

public class TriggerHelper {

    public static Boolean isRunning = false;

}

Trigger

trigger AccountTrigger on Account(before update){

    if(TriggerHelper.isRunning){
        return;
    }

    TriggerHelper.isRunning = true;

    //Business Logic

}

Problem with Static Boolean

Works only once.

Fails in Bulk Processing.

Suppose:

200 Records

↓

First 200 Processed

↓

Boolean = True

↓

Remaining Records Skipped

Not recommended.


Solution 2: Static Set (Recommended)

public class TriggerHelper{

    public static Set<Id> processedIds = new Set<Id>();

}

Trigger

for(Account acc : Trigger.new){

    if(!TriggerHelper.processedIds.contains(acc.Id)){

        TriggerHelper.processedIds.add(acc.Id);

        //Business Logic

    }

}

Now every record executes only once.


Real-Time Example

Requirement:

Whenever Account Rating changes,

Create one Task.

Without recursion:

Update Account

↓

Task Created

↓

Task Trigger Updates Account

↓

Account Trigger Runs Again

↓

Another Task Created

↓

Infinite Loop

Using Static Set prevents duplicate processing.


Best Practices

  • Prefer Static Set or Static Map over Static Boolean.
  • Keep triggers idempotent (same input = same result).
  • Avoid updating the same object inside its own trigger unless required.
  • Use Trigger Handler Framework.

Governor Limits / Performance

Recursion often leads to:

  • CPU Time Limit Exceeded
  • Maximum Trigger Depth Exceeded
  • Too Many SOQL Queries
  • Duplicate DML Operations

3. How Do You Bulkify an Apex Trigger?

Definition

Bulkification means writing Apex code that processes multiple records efficiently in a single execution instead of assuming only one record is processed.

Salesforce can pass up to 200 records to a trigger in one transaction.


Bad Example (Not Bulkified)

trigger AccountTrigger on Account(after insert){

    for(Account acc : Trigger.new){

        Contact con = new Contact(
            LastName='Test',
            AccountId=acc.Id
        );

        insert con;

    }

}

If 200 Accounts are inserted:

200 DML statements.

Governor Limit:

Maximum DML = 150

Transaction fails.


Good Example (Bulkified)

trigger AccountTrigger on Account(after insert){

    List<Contact> contacts = new List<Contact>();

    for(Account acc : Trigger.new){

        contacts.add(new Contact(
            LastName='Test',
            AccountId=acc.Id
        ));

    }

    insert contacts;

}

Only:

1 DML

instead of

200 DML

Bulk SOQL Example

Bad

for(Account acc : Trigger.new){

    Contact c = [
        SELECT Id
        FROM Contact
        WHERE AccountId=:acc.Id
    ];

}

200 SOQL Queries.

Governor Limit:

Maximum SOQL = 100

Fails.


Good

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

for(Account acc : Trigger.new){

    accountIds.add(acc.Id);

}

Map<Id,List<Contact>> accountContacts =
new Map<Id,List<Contact>>();

Then query all contacts in one SOQL and group them by AccountId.


Real-Time Example

Requirement:

When 500 Opportunities are inserted,

Create one Task per Opportunity.

Bulkified solution:

  • Collect all Tasks.
  • Insert once.
  • No SOQL inside loops.
  • No DML inside loops.

Best Practices

  • Use Collections (List, Set, Map).
  • Query once.
  • DML once.
  • Process all records together.
  • Assume 200 records every time.

Governor Limits / Performance

Bulkification reduces:

  • SOQL Count
  • DML Count
  • CPU Time
  • Heap Size

It significantly improves scalability.


4. What Is a Trigger Handler Framework, and Why Is It Important?

Definition

A Trigger Handler Framework separates business logic from the trigger itself. The trigger becomes a lightweight entry point that delegates work to Apex classes.

Instead of putting all logic directly inside the trigger, you organize it into reusable handler methods.


Traditional Trigger (Not Recommended)

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

    // Hundreds of lines of business logic

}

Problems:

  • Difficult to read.
  • Hard to test.
  • Hard to maintain.
  • Multiple developers editing the same trigger.

Trigger Handler Framework

Trigger

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

    AccountTriggerHandler handler =
        new AccountTriggerHandler();

    if(Trigger.isBefore){

        if(Trigger.isInsert){

            handler.beforeInsert(Trigger.new);

        }

        if(Trigger.isUpdate){

            handler.beforeUpdate(Trigger.new, Trigger.oldMap);

        }

    }

    if(Trigger.isAfter){

        if(Trigger.isInsert){

            handler.afterInsert(Trigger.new);

        }

        if(Trigger.isUpdate){

            handler.afterUpdate(Trigger.new, Trigger.oldMap);

        }

    }

}

Handler Class

public class AccountTriggerHandler{

    public void beforeInsert(List<Account> newList){

        //Business Logic

    }

    public void afterUpdate(List<Account> newList,
                            Map<Id,Account> oldMap){

        //Business Logic

    }

}

Real-Time Example

Company Requirements:

  • Before Insert → Validate PAN.
  • Before Update → Validate GST.
  • After Insert → Create Welcome Task.
  • After Update → Sync with ERP.

Each responsibility belongs in its own method, making the code easier to maintain.


Why Is It Important?

Benefits:

  • One Trigger Per Object
  • Separation of Concerns
  • Reusable Logic
  • Easier Unit Testing
  • Better Team Collaboration
  • Simplified Maintenance

Best Practices

  • Maintain one trigger per object.
  • Keep triggers logic-free.
  • Use service/helper classes for complex business logic.
  • Add recursion prevention in the handler layer.
  • Follow consistent naming conventions.

Governor Limits / Performance

A Trigger Handler Framework does not directly increase limits but helps you write bulkified, optimized code that avoids excessive SOQL, DML, and CPU usage.


5. How Do You Avoid SOQL and DML Inside Loops?

Definition

Executing SOQL queries or DML operations inside loops is one of the most common causes of Governor Limit exceptions in Salesforce.

The solution is to use collections and perform operations in bulk.


Bad Example

for(Account acc : Trigger.new){

    Contact con = [
        SELECT Id
        FROM Contact
        WHERE AccountId=:acc.Id
    ];

}

If 200 Accounts are processed:

200 SOQL Queries

Governor Limit:

Maximum SOQL = 100

The transaction fails.


Correct Approach

Step 1: Collect IDs.

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

for(Account acc : Trigger.new){

    accountIds.add(acc.Id);

}

Step 2: Query once.

List<Contact> contacts = [
    SELECT Id, AccountId
    FROM Contact
    WHERE AccountId IN :accountIds
];

Step 3: Process in memory using Maps or grouped collections.


DML Example

Bad

for(Account acc : Trigger.new){

    Task t = new Task(
        Subject='Follow Up',
        WhatId=acc.Id
    );

    insert t;

}

Good

List<Task> tasks = new List<Task>();

for(Account acc : Trigger.new){

    tasks.add(new Task(
        Subject='Follow Up',
        WhatId=acc.Id
    ));

}

insert tasks;

Only one DML statement is used.


Real-Time Example

Requirement:

Whenever 200 Accounts are created:

  • Check existing Contacts.
  • Create one Task for each Account.

Optimized approach:

  1. Gather Account IDs.
  2. Query all Contacts in one SOQL.
  3. Build a Map<Id, List<Contact>>.
  4. Create all Tasks in a List<Task>.
  5. Perform a single insert.

This approach is scalable and governor-limit friendly.


Best Practices

  • Never write SOQL inside a for loop.
  • Never perform DML inside a for loop.
  • Use Set to collect unique IDs.
  • Use Map for fast lookups.
  • Batch inserts, updates, and deletes whenever possible.
  • Always design code assuming up to 200 records per trigger execution.

Governor Limits / Performance

Key limits to remember:

Governor LimitValue
SOQL Queries100 (Synchronous)
DML Statements150
Records Retrieved by SOQL50,000
Records Processed in TriggerUp to 200 per batch
CPU Time10 seconds (Synchronous)

Following these practices results in:

  • Faster execution
  • Lower CPU consumption
  • Better scalability
  • Fewer governor-limit exceptions

6. How do you handle Mixed DML Operations?

Definition

Mixed DML occurs when you try to perform DML operations on Setup Objects and Non-Setup Objects in the same transaction.

Salesforce blocks this because Setup Objects affect user permissions and access, while Non-Setup Objects contain business data. Mixing them in one transaction could create inconsistent security states.


What are Setup Objects?

Examples:

  • User
  • UserRole
  • Group
  • GroupMember
  • QueueSObject
  • PermissionSetAssignment
  • Territory
  • Custom Settings (Hierarchy)

What are Non-Setup Objects?

Examples:

  • Account
  • Contact
  • Opportunity
  • Lead
  • Case
  • Custom Objects

Why does Salesforce throw Mixed DML?

Imagine this code:

Account acc = new Account(Name='ABC');
insert acc;

User u = new User(
    LastName='John',
    Alias='john',
    Email='john@test.com',
    Username='john@test.com',
    TimeZoneSidKey='Asia/Kolkata',
    LocaleSidKey='en_US',
    EmailEncodingKey='UTF-8',
    LanguageLocaleKey='en_US',
    ProfileId=profileId
);

insert u;

Error:

MIXED_DML_OPERATION:
DML operation on setup object is not permitted
after you have updated a non-setup object.

How It Works

Salesforce separates transactions involving security metadata from transactions involving business records.

To resolve Mixed DML:

  • Future Method
  • Queueable Apex
  • Platform Events
  • Scheduled Apex
  • Separate Transactions

Solution Using Future Method

public class UserService{

    @future

    public static void createUser(){

        //Insert User

    }

}

Trigger:

insert account;

UserService.createUser();

Now:

Transaction 1

Insert Account

↓

Commit

Transaction 2

Future Method

↓

Insert User

No Mixed DML.


Real-Time Example

Requirement:

When HR creates a new Employee record,

Automatically:

  • Create Contact
  • Create User
  • Assign Permission Set

Wrong Approach

Insert Employee

↓

Insert Contact

↓

Insert User

↓

Assign Permission Set

↓

Mixed DML Error

Correct Approach

Insert Employee

↓

Insert Contact

↓

Commit

↓

Queueable Apex

↓

Create User

↓

Assign Permission Set

Best Practices

  • Never insert User and Account together in one transaction.
  • Use Queueable instead of Future for new development.
  • Keep setup-related operations asynchronous.
  • Separate business data and security-related operations.

Governor Limits / Performance

Future Methods:

  • Maximum 50 future calls per transaction.
  • No chaining.

Queueable:

  • Better monitoring.
  • Supports chaining.
  • Preferred over Future.

Interview Follow-Up

Interviewer: Why does Queueable solve Mixed DML?

Answer:

Because Queueable runs in a separate transaction after the original transaction commits, so Setup and Non-Setup DML no longer occur together.


7. Future Method vs Queueable Apex vs Batch Apex

Definition

These are asynchronous Apex mechanisms used to execute code outside the current transaction.


Future Method

Purpose

Execute lightweight asynchronous tasks.

@future

public static void sendEmail(){

}

Features

  • Runs asynchronously.
  • Static methods only.
  • Primitive parameters only.
  • Cannot chain.
  • Limited monitoring.

Real-Time Example

After Opportunity closes,

Send email notification.

No need to wait for the email before saving the Opportunity.


Queueable Apex

Purpose

Perform asynchronous work with complex objects and support chaining.

public class MyQueueable
implements Queueable{

    public void execute(QueueableContext qc){

    }

}

Execute:

System.enqueueJob(new MyQueueable());

Advantages

  • Supports complex objects.
  • Supports chaining.
  • Job monitoring.
  • Better debugging.
  • Preferred over Future.

Real-Time Example

After Account creation:

  • Create Customer in ERP.
  • Generate PDF.
  • Upload File.
  • Call SAP API.

All handled asynchronously using Queueable.


Batch Apex

Purpose

Process millions of records.

global class BatchJob
implements Database.Batchable<SObject>{

}

Methods

start()

execute()

finish()

Salesforce processes records in chunks.

Example:

1,000,000 Accounts

↓

200

↓

200

↓

200

↓

Finish

Each batch gets fresh governor limits.


Comparison Table

FeatureFutureQueueableBatch Apex
AsynchronousYesYesYes
Complex ObjectsNoYesYes
ChainingNoYesYes (via finish)
MonitoringLimitedGoodExcellent
Millions of RecordsNoNoYes
Governor Limits ResetNoNoYes (per batch)
RecommendedLegacy useMost async tasksLarge data volumes

Best Practices

Use:

Future

  • Small async work.
  • Existing legacy code.

Queueable

  • API callouts.
  • Complex processing.
  • File generation.
  • Preferred for new development.

Batch

  • Data cleanup.
  • Mass updates.
  • Scheduled nightly jobs.
  • Millions of records.

Governor Limits

Queueable:

  • 50 enqueueJob calls per transaction.

Batch:

  • Default batch size = 200.
  • Fresh governor limits for every execute().

Interview Tip

If asked:

“Which one would you choose?”

Answer:

Queueable Apex for most asynchronous business logic because it supports complex objects, chaining, monitoring, and is the modern replacement for Future Methods.


8. When would you use Database methods instead of DML statements?

Definition

Salesforce provides two ways to perform DML:

Standard DML

insert accounts;
update accounts;
delete accounts;

Database Class

Database.insert(accounts,false);

Difference

Standard DML

If one record fails,

Entire transaction rolls back.

Database Methods

Can allow partial success.


Example

Insert 100 Accounts.

Record 45 has missing Name.

Using insert

100 Records

↓

1 Error

↓

Everything Fails

Using Database.insert

Database.SaveResult[] results =
Database.insert(accounts,false);

Result

99 Records Inserted

↓

1 Failed

SaveResult Example

for(Database.SaveResult sr : results){

    if(sr.isSuccess()){

    }else{

        System.debug(sr.getErrors());

    }

}

Real-Time Example

Importing 50,000 Leads.

Some rows have invalid Email.

Business Requirement:

Import valid Leads.

Skip invalid Leads.

Database methods are the correct choice.


Best Practices

Use Standard DML

  • When all records must succeed.

Use Database Methods

  • Data migration.
  • Bulk imports.
  • ETL jobs.
  • Batch Apex.
  • Integrations requiring partial success.

Governor Limits

Database methods count toward DML limits just like standard DML, but they give better control over error handling and partial processing.


Interview Follow-Up

Interviewer: What does false mean in Database.insert(records,false)?

Answer:

It sets allOrNone = false, allowing Salesforce to save valid records while returning errors only for invalid ones instead of rolling back the entire transaction.


9. Explain Governor Limits with Real Examples

Definition

Governor Limits are limits enforced by Salesforce to ensure that one customer’s code does not consume excessive shared resources in the multi-tenant platform.

Think of Salesforce as an apartment building where every tenant shares electricity and water. Governor Limits ensure that no single tenant uses all the resources.


Why Governor Limits Exist

Salesforce uses a multi-tenant architecture, where thousands of organizations share the same infrastructure. Limits protect platform stability and fairness.


Common Governor Limits

LimitSynchronous
SOQL Queries100
DML Statements150
Records Retrieved50,000
CPU Time10 Seconds
Heap Size6 MB
Callouts100

Real Example 1

Bad Code

for(Account acc : Trigger.new){

    Contact c=[
        SELECT Id
        FROM Contact
        WHERE AccountId=:acc.Id
    ];

}

200 Accounts

200 SOQL

Limit = 100

Exception

Too many SOQL queries:101

Real Example 2

for(Account acc : Trigger.new){

    insert new Task();

}

200 Records

200 Inserts

Limit =150

Too many DML statements:151

Real Example 3

Infinite recursion.

Trigger executes repeatedly.

CPU reaches 10 seconds.

Apex CPU Time Limit Exceeded

Best Practices

  • Bulkify code.
  • Use Collections.
  • Avoid SOQL in loops.
  • Avoid DML in loops.
  • Prevent recursion.
  • Use asynchronous processing for long-running work.
  • Cache repeated lookups where appropriate.

Performance Optimization

Instead of:

SOQL

↓

SOQL

↓

SOQL

↓

SOQL

Do:

One SOQL

↓

Map

↓

Lookup in Memory

Memory operations are much faster than repeated database queries.


Interview Tip

A strong answer explains not just the limits but how your coding practices avoid hitting them.


10. How do you optimize Apex code hitting CPU Time Limit?

Definition

The CPU Time Limit is the maximum processing time Salesforce allows for Apex execution in a single transaction.

Current synchronous limit:

10 seconds

If exceeded:

Apex CPU Time Limit Exceeded

Common Causes

  • Nested loops.
  • Infinite recursion.
  • SOQL inside loops.
  • DML inside loops.
  • Repeated calculations.
  • Large collections processed inefficiently.
  • Too many automation tools firing in the same transaction.

Bad Example

for(Account acc : accounts){

    for(Contact con : contacts){

        if(acc.Id==con.AccountId){

        }

    }

}

If:

Accounts = 10,000

Contacts = 20,000

Iterations

10,000 × 20,000

=

200 Million Comparisons

This is highly inefficient.


Optimized Example

Map<Id,List<Contact>> accountContacts =
new Map<Id,List<Contact>>();

Now

Account

↓

Map Lookup

↓

O(1)

instead of scanning the entire Contact list for every Account.


Additional Optimization Techniques

Use Collections

Replace nested loops with Map, Set, or grouped lists for constant-time lookups.

Reduce Database Calls

  • Query only required fields.
  • Perform one bulk query instead of many.
  • Move expensive work to asynchronous Apex if it doesn’t need to finish immediately.

Prevent Recursion

Use static sets/maps or handler frameworks to avoid unnecessary trigger re-entry.

Simplify Logic

Break large methods into reusable helper methods and eliminate duplicate calculations.


Real-Time Example

Requirement:

Updating 50,000 Opportunities recalculates Territory and Revenue.

Initial implementation:

  • Nested loops
  • Multiple queries
  • Trigger recursion

Result:

CPU Time Limit Exceeded

Optimized solution:

  • Single SOQL query.
  • Maps for lookups.
  • Trigger Handler Framework.
  • Queueable Apex for ERP sync.
  • Batch Apex for large-volume recalculation.

The transaction completed successfully within governor limits.


Best Practices

  • Replace nested loops with Maps whenever possible.
  • Use Trigger Handler Frameworks.
  • Bulkify all logic.
  • Process non-critical work asynchronously.
  • Profile and refactor expensive algorithms.
  • Keep trigger logic focused and lightweight.

Governor Limits / Performance

Key CPU-related limits:

MetricLimit
CPU Time (Synchronous)10 seconds
CPU Time (Asynchronous)60 seconds

Optimizing CPU usage improves:

  • Faster transaction completion.
  • Better scalability.
  • Reduced governor-limit failures.
  • Improved user experience.

11. How do you process millions of records using Batch Apex?

Definition

Batch Apex is an asynchronous Apex feature that processes large volumes of records (thousands to millions) by dividing them into smaller chunks (batches). Each batch executes as a separate transaction with its own governor limits.

Use Batch Apex when:

  • Updating millions of records
  • Data migration
  • Scheduled data cleanup
  • Nightly jobs
  • Large data synchronization

How It Works

Batch Apex implements the Database.Batchable interface and has three methods:

global class AccountBatch implements Database.Batchable<SObject> {

    global Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator(
            'SELECT Id, Name FROM Account'
        );
    }

    global void execute(Database.BatchableContext bc, List<Account> scope) {

        for(Account acc : scope){
            acc.Description = 'Processed';
        }

        update scope;
    }

    global void finish(Database.BatchableContext bc){
        System.debug('Batch Completed');
    }
}

Execute the batch:

Database.executeBatch(new AccountBatch(), 200);

Batch Execution Flow

1,000,000 Accounts
        │
        ▼
Query Records (start)
        │
        ▼
Batch 1 (200 Records)
        │
        ▼
Batch 2 (200 Records)
        │
        ▼
Batch 3 (200 Records)
        │
        ▼
...
        │
        ▼
finish()

Each batch executes independently.


Why is Batch Apex Powerful?

Every execution of execute() receives fresh governor limits.

Example:

Batch 1

SOQL = 100

CPU = 60 sec

↓

Batch 2

SOQL Reset

CPU Reset

↓

Batch 3

Again Reset

This makes Batch Apex suitable for processing millions of records.


Real-Time Example

Requirement

Every night:

  • Update 3 million Opportunities.
  • Recalculate Commission.
  • Archive Closed Opportunities.
  • Send summary email to Admin.

Solution:

  • Scheduled Apex starts the Batch Job.
  • Batch processes 200 records at a time.
  • finish() sends the completion email.

Batch Size

Default:

200 Records

Can be customized:

Database.executeBatch(new AccountBatch(),100);

Choose the batch size based on processing complexity.


QueryLocator vs Iterable

QueryLocator

Database.getQueryLocator()

Supports:

50 Million Records

Best for Salesforce object queries.


Iterable

Iterable<SObject>

Used when:

  • Data comes from an API.
  • Data is generated dynamically.
  • Data isn’t retrieved via SOQL.

Stateful Batch

Normally:

Variables reset after each batch.

Using:

implements Database.Stateful

Variables retain values across batches.

Example:

global Integer totalUpdated = 0;

Each batch increments the count.

At the end:

Total Updated = 2,450,000

Best Practices

  • Process only required fields.
  • Keep execute() lightweight.
  • Use QueryLocator for large SOQL queries.
  • Use Database.Stateful only when necessary.
  • Perform notifications in finish().

Governor Limits / Performance

Per execute():

LimitValue
SOQL Queries100
DML Statements150
CPU Time60 Seconds
Heap Size12 MB

Fresh limits are applied to every batch.


Interview Follow-Up

Interviewer: Why does Batch Apex handle millions of records while Queueable cannot?

Answer:

Queueable runs as a single transaction, whereas Batch Apex splits work into multiple transactions. Each transaction gets fresh governor limits, making Batch Apex scalable for very large datasets.


12. Explain Savepoints and Rollbacks

Definition

A Savepoint marks a checkpoint within a transaction. If an error occurs later, you can rollback to that checkpoint instead of committing partial changes.

This helps maintain data consistency.


How It Works

Savepoint sp = Database.setSavepoint();

try{

    insert account;

    insert contact;

}catch(Exception e){

    Database.rollback(sp);

}

Transaction Flow

Start Transaction
        │
        ▼
Savepoint Created
        │
        ▼
Insert Account
        │
        ▼
Insert Contact
        │
        ▼
Error Occurs
        │
        ▼
Rollback
        │
        ▼
Database Returns to Savepoint

No partial data remains.


Real-Time Example

Requirement:

Create:

  • Account
  • Contact
  • Opportunity

If Opportunity creation fails,

Undo everything.

Solution:

Savepoint sp = Database.setSavepoint();

try{

    insert acc;

    insert con;

    insert opp;

}catch(Exception e){

    Database.rollback(sp);

}

Why Not Use Separate DML?

Without rollback:

Account Created

↓

Contact Created

↓

Opportunity Failed

↓

Database Inconsistent

Rollback ensures either all changes succeed or none are committed.


Best Practices

  • Create savepoints only when needed.
  • Roll back only on business-critical failures.
  • Avoid unnecessary nested savepoints.

Governor Limits

Maximum Savepoints per transaction:

5

Interview Follow-Up

Interviewer: Does rollback undo emails or callouts?

Answer:

No. Rollback only reverses database changes within the transaction. External actions (such as emails already sent or completed callouts) are not undone.


13. What is Dynamic Apex?

Definition

Dynamic Apex allows your code to inspect metadata and manipulate objects at runtime instead of hardcoding object names and fields.

It enables generic, reusable solutions.


Static Apex

Account acc = new Account();
acc.Name='ABC';

Object is fixed.


Dynamic Apex

SObject obj = Schema.getGlobalDescribe()
                    .get('Account')
                    .newSObject();

obj.put('Name','ABC');

Object is determined at runtime.


Dynamic SOQL

String objectName='Account';

String query='SELECT Id,Name FROM '+objectName;

List<SObject> records = Database.query(query);

Dynamic Fields

String fieldName='Name';

String value=(String)obj.get(fieldName);

Real-Time Example

Requirement:

Build one utility that exports data from:

  • Account
  • Contact
  • Lead
  • Opportunity

Instead of writing four classes,

Create one generic Dynamic Apex utility.


Schema Describe

Map<String,Schema.SObjectType> objects =
Schema.getGlobalDescribe();

Retrieve fields:

Schema.SObjectType accountType =
Schema.getGlobalDescribe().get('Account');

Map<String,Schema.SObjectField> fields =
accountType.getDescribe().fields.getMap();

Best Practices

  • Validate object and field names before using them.
  • Avoid Dynamic SOQL when static SOQL is sufficient.
  • Use bind variables whenever possible to prevent SOQL injection.

Governor Limits / Performance

Dynamic Apex is slightly slower than static Apex because Salesforce must evaluate metadata at runtime. Use it only where flexibility is required.


Interview Follow-Up

Interviewer: Where have you used Dynamic Apex in a project?

Answer:

I used Dynamic Apex to build a configurable data export utility that worked for multiple standard and custom objects without writing object-specific code.


14. How do you implement Custom Metadata in Apex?

Definition

Custom Metadata Types (CMDT) store configuration data that can be deployed between environments and accessed in Apex.

Unlike Custom Settings, metadata records are treated as metadata rather than business data.


Why Use Custom Metadata?

Instead of hardcoding values:

if(country == 'India'){
    tax = 18;
}

Store:

CountryTax
India18
USA8
UK20

Admins can update configuration without modifying Apex code.


Apex Example

Tax_Config__mdt config =
Tax_Config__mdt.getInstance('India');

Decimal tax=config.Tax__c;

Real-Time Example

Requirement:

Discount percentage differs by country.

Instead of hardcoding:

India → 15%

USA → 10%

Germany → 20%

Store these values in Custom Metadata.

Whenever the business changes the percentage, the admin updates metadata instead of requesting a code deployment.


Benefits

  • Deployable via Change Sets or DevOps tools.
  • Cached by Salesforce for faster access.
  • Eliminates hardcoded values.
  • Easy for admins to maintain.

Best Practices

  • Use Custom Metadata for business configuration.
  • Use meaningful record names.
  • Avoid hardcoding IDs or constants in Apex.
  • Document metadata usage clearly.

Governor Limits / Performance

Custom Metadata is optimized by Salesforce and is generally faster than querying normal objects for configuration values. It also reduces maintenance effort.


Interview Follow-Up

Interviewer: When would you use Custom Metadata instead of Custom Settings?

Answer:

Use Custom Metadata for deployable application configuration shared across environments. Use Custom Settings when configuration is organization-specific or user/profile-specific and may change directly in production.


15. Explain the with sharing, without sharing, and inherited sharing keywords

Definition

These keywords determine whether Apex code enforces the organization’s record-level sharing rules.

They do not enforce Object-Level Security (OLS) or Field-Level Security (FLS); those must be handled separately.


1. with sharing

public with sharing class AccountService{

}

Respects:

  • Organization-Wide Defaults (OWD)
  • Role Hierarchy
  • Sharing Rules
  • Manual Sharing

User sees only records they are allowed to access.


Example

Sales User owns:

Account A

Cannot access:

Account B

Using:

with sharing

Query:

SELECT Id FROM Account

Returns only:

Account A

2. without sharing

public without sharing class AccountService{

}

Ignores record-level sharing.

The code can access all records permitted by object permissions.


Real-Time Example

Nightly integration:

ERP system must synchronize every Account regardless of ownership.

Use:

without sharing

to process all records.


3. inherited sharing

public inherited sharing class AccountService{

}

The class inherits the sharing behavior of the calling context.

If called from:

with sharing

it respects sharing.

If called from:

without sharing

it runs without sharing.


Comparison Table

KeywordRecord-Level Sharing
with sharingEnforced
without sharingIgnored
inherited sharingInherits caller’s context

Real-Time Scenario

Requirement:

Customer Portal users should see only their own Cases.

Solution:

public with sharing class CaseController{

}

Another requirement:

Nightly integration exports every Case to SAP.

Solution:

public without sharing class SAPSync{

}

Best Practices

  • Default to with sharing unless there is a justified reason not to.
  • Use without sharing only for trusted system processes or integrations.
  • Prefer inherited sharing for reusable service classes so behavior follows the caller’s security context.
  • Always enforce Object-Level Security (OLS) and Field-Level Security (FLS) separately using APIs such as WITH USER_MODE, Security.stripInaccessible(), or appropriate access checks.

Governor Limits / Performance

Sharing keywords primarily affect security, not governor limits. However:

  • with sharing may return fewer records, reducing processing time.
  • without sharing can return significantly more data, so ensure queries remain selective and bulkified.

16. How do you write Exception Handling in Apex?

Definition

Exception Handling is a mechanism used to catch and handle runtime errors gracefully so that the application does not fail unexpectedly.

Instead of allowing the transaction to terminate with an unhandled exception, Apex provides try, catch, and finally blocks to manage errors.


How It Works

try{
    // Business Logic
}
catch(Exception e){
    // Handle Error
}
finally{
    // Always Executes
}

Execution Flow:

Start
   │
   ▼
Try Block
   │
   ├── No Error ───────────────► Finally ► End
   │
   └── Error Occurs
           │
           ▼
      Catch Block
           │
           ▼
      Finally Block
           │
           ▼
           End

Common Exception Types

ExceptionWhen It Occurs
DmlExceptionInsert/Update/Delete failure
QueryExceptionSOQL returns unexpected results
NullPointerExceptionAccessing a null object
ListExceptionInvalid list index
MathExceptionDivision by zero
JSONExceptionInvalid JSON parsing
CalloutExceptionHTTP callout failure

Example

try{

    Account acc = new Account();

    insert acc;

}catch(DmlException ex){

    System.debug(ex.getMessage());

}

Multiple Catch Blocks

try{

    // Logic

}catch(DmlException e){

}

catch(QueryException e){

}

catch(Exception e){

}

Always catch the most specific exceptions before the generic Exception.


Real-Time Example

Requirement:

When an Opportunity is Closed Won:

  • Create Invoice
  • Create Payment
  • Call ERP API

If ERP API fails:

  • Log the error
  • Notify the Admin
  • Retry asynchronously
  • Prevent inconsistent business processing where appropriate

Logging Errors

Instead of only:

System.debug(e);

Create a custom logging solution.

Example:

Custom Object

Error Log

----------------

Class Name

Method

Stack Trace

Date

User

Record Id

This makes production troubleshooting much easier.


Best Practices

  • Catch specific exceptions whenever possible.
  • Never use an empty catch block.
  • Log meaningful error details.
  • Show user-friendly messages in UI contexts.
  • Separate business logic from exception handling.
  • Consider retry strategies for transient integration failures.

Governor Limits / Performance

Exception handling itself has minimal overhead. However:

  • Avoid using exceptions for normal control flow.
  • Excessive logging or repeated retries can impact CPU time and DML limits.

Interview Follow-Up

Interviewer:

Why shouldn’t we write:

catch(Exception e){}

Answer:

Because it silently hides errors, making debugging and production support extremely difficult. Every exception should either be handled appropriately, logged, or rethrown if necessary.


17. How do you test Asynchronous Apex?

Definition

Asynchronous Apex (Future, Queueable, Batch, Scheduled) runs after the current transaction.

In unit tests, asynchronous jobs do not execute automatically unless wrapped between:

Test.startTest();

Test.stopTest();

How It Works

Test.startTest();

System.enqueueJob(new MyQueueable());

Test.stopTest();

When stopTest() executes:

  • Queueable runs.
  • Future Methods run.
  • Batch Apex executes.
  • Scheduled Apex executes (if scheduled during the test).

Queueable Example

@IsTest

private class QueueTest{

    @IsTest

    static void testQueue(){

        Test.startTest();

        System.enqueueJob(new MyQueue());

        Test.stopTest();

    }

}

Future Method Test

Test.startTest();

MyFutureClass.sendEmail();

Test.stopTest();

Batch Test

Test.startTest();

Database.executeBatch(new AccountBatch(),200);

Test.stopTest();

Scheduled Apex Test

String cron='0 0 12 * * ?';

Test.startTest();

System.schedule(
    'MyJob',
    cron,
    new MyScheduler()
);

Test.stopTest();

Real-Time Example

Requirement:

When an Opportunity is Closed Won:

  • Trigger calls Queueable.
  • Queueable calls SAP API.
  • Response updates Opportunity.

Testing Steps:

  1. Insert test Opportunity.
  2. Update Stage to Closed Won.
  3. Call Test.stopTest().
  4. Verify the Queueable updated the record as expected (mock external callouts where applicable).

Best Practices

  • Always wrap async code with Test.startTest() and Test.stopTest().
  • Use HttpCalloutMock for testing callouts.
  • Assert business outcomes, not just execution.
  • Create isolated test data.

Governor Limits

Test.startTest() resets governor limits, providing a fresh set of limits for the code under test.


Interview Tip

Many candidates know startTest() and stopTest(). Strong candidates also explain why they are needed and how they enable testing of asynchronous behavior.


18. How do you achieve 90%+ code coverage with meaningful test cases?

Definition

Salesforce requires at least:

75%

overall Apex code coverage to deploy to production.

However:

High code coverage does not guarantee high-quality tests.

A meaningful test verifies business behavior, edge cases, and error handling.


Good Testing Strategy

Cover:

  • Positive scenarios
  • Negative scenarios
  • Bulk operations
  • Exception handling
  • Permission/security scenarios (where applicable)
  • Null values
  • Boundary conditions

Example

Trigger:

If Opportunity Amount > 100000

Create Approval Task.

Tests should verify:

✔ Amount = 200000

Task Created.

✔ Amount = 5000

Task Not Created.

✔ 200 Opportunities

Bulk Processing Works.

✔ Invalid Data

Proper error handling.


Test Data

Use:

@testSetup

Example:

@testSetup

static void setup(){

    insert new Account(Name='ABC');

}

The same data is reused across test methods, improving readability and performance.


Assertions

Never write tests like:

System.assert(true);

Instead:

System.assertEquals(1,tasks.size());

Verify expected outcomes.


Real-Time Example

Requirement:

Trigger creates Contact automatically.

Test Cases:

  • One Account
  • 200 Accounts
  • Missing Name
  • Duplicate Data
  • Existing Contact
  • Exception Scenario

Best Practices

  • Focus on business logic, not just line coverage.
  • Use reusable test data.
  • Keep tests independent.
  • Use descriptive test method names.
  • Verify both success and failure scenarios.

Governor Limits

Tests execute within governor limits, so bulk test cases also validate that your code remains governor-limit compliant.


Interview Follow-Up

Interviewer:

Is 100% coverage always better?

Answer:

Not necessarily. Well-designed tests with meaningful assertions are more valuable than simply achieving 100% coverage.


19. What is Platform Cache, and when would you use it?

Definition

Platform Cache is an in-memory storage feature that allows Apex to temporarily store frequently used data.

Instead of repeatedly querying the database, Apex retrieves the value directly from cache.

This reduces:

  • SOQL Queries
  • CPU Time
  • Database Load

How It Works

Without Cache

Request

↓

SOQL

↓

Database

↓

Response

Every request hits the database.


With Cache

Request

↓

Cache

↓

Value Found

↓

Return Immediately

Database access is skipped.


Cache Types

Session Cache

Data is available only during the user’s session.

Examples:

  • Shopping cart
  • Wizard progress
  • Temporary preferences

Organization Cache

Shared across users.

Examples:

  • Tax rates
  • Exchange rates
  • Country codes
  • Product configuration

Apex Example

Store:

Cache.Org.put('TaxRate',18);

Retrieve:

Integer tax=(Integer)Cache.Org.get('TaxRate');

Real-Time Example

Requirement:

Every Opportunity calculation needs the GST percentage.

Without Cache:

1000 Opportunities

↓

1000 SOQL Queries

With Cache:

Load Once

↓

Platform Cache

↓

Reuse Value

Performance improves significantly.


Best Practices

  • Cache read-heavy, infrequently changing data.
  • Do not cache sensitive or rapidly changing information.
  • Handle cache misses by reloading the value from the source.
  • Use appropriate expiration policies.

Governor Limits / Performance

Platform Cache helps reduce:

  • SOQL consumption
  • CPU time
  • Database load

Remember that cached data is temporary and may expire or be evicted, so your code should always handle cache misses gracefully.


Interview Follow-Up

Interviewer:

Should customer balances be stored in Platform Cache?

Answer:

Generally, no. Financial balances change frequently and require strong consistency. Platform Cache is better suited for relatively stable reference or configuration data.


20. Explain a production issue you resolved using Apex

This is a behavioral interview question. Interviewers want to understand how you diagnose problems, communicate, and deliver reliable fixes.

A structured STAR (Situation, Task, Action, Result) answer works well.


Production Scenario 1 (CPU Time Limit)

Situation

Users reported that updating an Opportunity with many related records failed.

Error:

Apex CPU Time Limit Exceeded

Investigation

I reviewed:

  • Debug Logs
  • Apex Execution Overview
  • Trigger Execution
  • Flow Execution

I found:

  • Nested loops.
  • Duplicate SOQL queries.
  • Trigger recursion.

Action

I:

  • Replaced nested loops with Map<Id, SObject>.
  • Bulkified the trigger.
  • Added recursion prevention.
  • Moved ERP synchronization to Queueable Apex.
  • Removed redundant queries.

Result

  • CPU time reduced significantly.
  • No more governor-limit exceptions.
  • Faster record saves.
  • Improved user experience.

Production Scenario 2 (Duplicate Tasks)

Situation

Every Account update created multiple duplicate Tasks.


Root Cause

Workflow Field Updates caused the trigger to execute again within the same transaction.


Solution

Implemented:

  • Trigger Handler Framework.
  • Static Set-based recursion prevention.
  • Idempotent business logic to avoid duplicate task creation.

Result

Duplicate Tasks were eliminated without affecting existing functionality.


Production Scenario 3 (Integration Failure)

Situation

ERP integration failed during peak business hours due to temporary network issues.


Root Cause

The trigger performed a synchronous callout, making record saves dependent on the external system.


Solution

  • Moved integration to Queueable Apex.
  • Added retry logic.
  • Logged failures in a custom error object.
  • Notified administrators for repeated failures.

Result

  • Users could save records without waiting.
  • Integration became more resilient.
  • Failures were traceable and recoverable.

Best Practices for Answering Production Issue Questions

When answering in an interview:

  1. Clearly explain the business problem.
  2. Describe how you investigated it.
  3. Explain the technical solution.
  4. Quantify the outcome if possible.
  5. Mention preventive improvements implemented afterward.

Sample Interview Answer

In one project, users experienced Apex CPU Time Limit Exceeded while updating Opportunities. I analyzed debug logs and found nested loops, repeated SOQL queries, and trigger recursion. I refactored the code using Maps, bulkified the logic, implemented a Trigger Handler Framework with recursion prevention, and moved ERP synchronization to Queueable Apex. After deployment, transaction times improved significantly, governor-limit exceptions stopped, and users were able to save records reliably even during peak business hours.


📚 Best Salesforce Interview Preparation Resources (2026)


📘 Admin Q&A Pack — recruiter-asked, real answers

🔗 https://lnkd.in/dKQPXK86

⚡ LWC Q&A Pack — with code & live scenarios

🔗 https://lnkd.in/gHwiZeGK

🔥 1000+ Real Salesforce Questions — asked in TCS, Infosys, EY, Wipro, Nagarro & more

🔗 https://lnkd.in/gFs-CkxT

💼 Mid-Senior (4–8 YOE) — curated Q&A set

🔗 https://lnkd.in/dXVeaCmS

💻 Data Engineer Interview Mega Pack — Azure | Databricks | SQL | ADF

🔗 https://lnkd.in/dFfsS4MQ

TrailheadTitans

At TrailheadTitans.com, we are dedicated to paving the way for both freshers and experienced professionals in the dynamic world of Salesforce. Founded by Abhishek Kumar Singh, a seasoned professional with a rich background in various IT companies, our platform aims to be the go-to destination for job seekers seeking the latest opportunities and valuable resources.

Leave a Comment

Item added to cart.
0 items - 0.00