Skip to content
Salesforce Interview Q&A 18 min read 5 sections

Salesforce Interview Questions Asked at KPMG India (L1 and L2)

KPMG India runs Salesforce developer hiring in two rounds. L1 is technical, taken by a senior developer or tech lead, and it moves fast across Apex, LWC, deployment and governor limits. L2 is techno-managerial, usually with a manager or architect, and the questions change shape: fewer definitions, m

RL

RizeX Labs

RizeX Labs

Published

Last updated

Related programme

Salesforce Training

Admin, Apex, Lightning Web Components and integrations in a live batch, with an industry project, mock interviews and a network of 270 hiring companies.

See the curriculum

3000+ learners · 270+ hiring partners

KPMG India runs Salesforce developer hiring in two rounds. L1 is technical, taken by a senior developer or tech lead, and it moves fast across Apex, LWC, deployment and governor limits. L2 is techno-managerial, usually with a manager or architect, and the questions change shape: fewer definitions, more design reasoning, more probing of what you actually built. Two questions are repeated across both rounds, which is deliberate. Below are all 22 questions in the order they were asked, with answers written the way you should give them in the room.

L1 Round (Technical)

1. What all integrations have you done in your project

Name the patterns you used and what each one carried.

REST API integration. The most common. Salesforce calls out over HTTP using Apex callouts, Named Credentials for endpoint and authentication, and Custom Metadata for anything environment specific. Used for payment gateways, order management and customer portals.

Inbound integration. The external system pushes into Salesforce, such as leads from a marketing tool or orders from ERP. You expose an Apex REST service, publish a Platform Event, or let middleware write.

SOAP integration. Mostly legacy systems. Salesforce generates Apex stub classes from the WSDL using WSDL2Apex.

Middleware integration. For anything complex, MuleSoft sits between the two, giving you transformation, retry, centralized security and monitoring in one place instead of rebuilding all of it in Apex.

Our trainers see the same failure here. The candidate says yes to "do you know integrations", the interviewer asks where, and the room goes quiet. Name the system, the direction of data, the authentication and the volume.

2. Have you done any POC

Yes, and say what it proved. A POC runs before full implementation to confirm the proposed solution will work, so the design is not finalised on an assumption.

For a payment gateway POC the goals are to verify API connectivity, validate the authentication method and the request and response structure, and measure response time. You study the API documentation, configure Named Credentials, build a basic Apex callout, send a request to the sandbox endpoint, log the response, and validate the data returned. Once it succeeds, the architecture is finalised.

If you have never run one, say so. Follow-up questions on a POC go five levels deep and a fabricated one collapses at level two.

3. How deployment is done in current project ? Deployment tools worked on

Deployment strategy depends on the maturity of the project.

Change Sets suit smaller teams. Developer sandbox to UAT sandbox to production. Manual and easy to miss components.

Salesforce CLI with Git is the standard in DevOps setups. Developer to Git repository to CI/CD pipeline to deployment, so metadata sits in version control with history and rollback.

CI/CD tools you will hear named are Jenkins, GitHub Actions and Azure DevOps. A pipeline runs code commit, build validation, test execution, deployment to target org.

Say which one your project used and why. Change Sets in a two-person team is a fine answer. A Jenkins pipeline you never touched is not.

4. Difference between querylocator and iterable

Both are return types for start() in Batch Apex.

Database.QueryLocator Iterable
Source A SOQL query Any custom data source
Ceiling Up to 50 million records Capped at 50,000 rows if built from SOQL
Chunking Salesforce handles it You control the iteration
Best for Large datasets, standard object queries External API data, records needing custom processing first
global Database.QueryLocator start(Database.BatchableContext bc) {
    return Database.getQueryLocator('SELECT Id FROM Account WHERE Active__c = true');
}

QueryLocator is optimised for retrieving Salesforce data. Iterable is for when custom iteration logic is required, such as external system records feeding the batch.

5. In UAT test class coverage is 85%, but while deploying to PROD it is getting failed showing coverage 0%, reason?

The best question in the L1 set, and it separates people who have deployed from people who have only coded. Coverage does not travel with your metadata. It is recomputed by running the tests in the target org at deploy time. So 0% means the tests either did not go, did not run, or ran and died.

Work through the causes in this order.

The test classes were not in the deployment package. The most common cause. The developer selected the Apex classes and triggers in the Change Set or manifest and left out the test classes. The new classes land in production with nothing covering them, so coverage is genuinely zero. Check package.xml or the component list first.

The test methods fail in production. A test that throws covers nothing. Lines executed before the failure are not credited if the test does not pass, so one broken test does not shave a few points off. It takes the class it was covering to zero.

The test depends on data that exists only in UAT. If it queries a record by name, by a hardcoded Id, or by a record type that was never deployed, the query returns nothing in production and the test dies at the first assert.

// Bad: passes in UAT only because someone created that Account there
Account a = [SELECT Id FROM Account WHERE Name = 'Test Account' LIMIT 1];

// Good: the test creates what it needs
@TestSetup
static void makeData() {
    insert new Account(Name = 'Test Account');
}

SeeAllData=true. The test reads whatever org data happens to exist. UAT has the records, production does not, and behaviour changes. Create all required test data inside the test class.

Missing configuration in production. Custom Settings, Custom Metadata records, Named Credentials and Custom Labels are not always deployed alongside code. If the class reads a Custom Setting on its first line and that setting is absent, every test fails there and coverage reads zero.

Stale coverage in the sandbox. The percentage shown in the sandbox comes from the last test run, not from now. If the class was edited afterwards, that 85% describes an older version of the code.

To prevent the situation, run the tests in the target org before you need them. A validation-only deployment executes the full test run against production and reports real coverage without committing anything.

sf project deploy validate --source-dir force-app --test-level RunLocalTests --target-org production

Close with the rule: production needs 75% coverage org wide, every trigger needs some coverage, and all tests must pass.

6. Batch running fine in UAT, in PROD we get error "Too many query rows: 50001", why, how to resolve it?

Same shape as the previous question and the same root cause. UAT may hold a few hundred records. Production holds hundreds of thousands or millions.

The limit. Maximum SOQL rows retrieved in a single transaction is 50,000. Row 50,001 throws. It counts rows retrieved, not queries issued, so one unfiltered query is enough on its own.

Why Batch Apex confuses people here. Records returned by a Database.QueryLocator in start() do not count toward the 50,000 row limit. That is the entire point of QueryLocator and why it spans 50 million records. So if a batch is hitting 50,001, the offending query is almost always one of these:

  • start() returns a List or an Iterable built from SOQL rather than a QueryLocator. That query is ordinary and capped at 50,000.
  • A query inside execute() that is not scoped to the current batch. Each execute() call is its own transaction with its own 50,000 row budget, and an unfiltered child query burns it instantly.
  • A trigger or handler firing inside the batch that runs its own broad query.
// Bad: ignores the scope and pulls every contact in the org
global void execute(Database.BatchableContext bc, List<Account> scope) {
    List<Contact> all = [SELECT Id, AccountId FROM Contact];
}

// Good: bind to the scope, select only the fields you use
global void execute(Database.BatchableContext bc, List<Account> scope) {
    List<Contact> related = [
        SELECT Id, AccountId FROM Contact
        WHERE AccountId IN :scope AND Active__c = true
    ];
}

To resolve it: use Database.getQueryLocator() in start() instead of returning a list, filter on an indexed field so the query stays selective as the object grows, bind every child query to the current scope, remove queries you do not need, never query inside a loop, and lower the batch size in Database.executeBatch(job, 50) if each record pulls a lot of related data.

The one-line version: the code was written against a data volume that does not exist in production. Our trainers push candidates to say exactly that, because it is the sentence the interviewer is waiting for.

7. Best practices for Test classes

  • No SeeAllData=true. Create test data inside the class every time.
  • Use Test.startTest() and Test.stopTest(). They give the tested code fresh governor limits, and stopTest() forces asynchronous code such as @future, Queueable and Batch to finish so you can assert on the result.
  • Test positive and negative scenarios. Valid data, invalid data, exception paths.
  • Use a test data factory. Reusable creation methods survive a new required field.
  • Maintain high coverage. Minimum 75%, practical target 85% to 90%.
  • Assert something. A test with no System.assertEquals() produces coverage and proves nothing.

8. Parent to child , child to parent communication

Parent to child. The parent passes data down through public properties on the child, decorated with @api.

// child.js
import { LightningElement, api } from 'lwc';
export default class Child extends LightningElement {
    @api recordName;
}
<!-- parent.html -->
<c-child record-name={accountName}></c-child>

Child to parent. The child fires a custom event and the parent listens. The child never reaches into the parent, which keeps them loosely coupled.

this.dispatchEvent(new CustomEvent('rowselect', { detail: this.selectedId }));

For components with no parent and child relationship, mention Lightning Message Service.

9. Explain track and wire. Use cases of both

@track made object properties reactive so the UI re-rendered when a property inside an object changed. Fields are now reactive by default, so it is needed only when you mutate a property inside an object or array in place rather than reassigning it.

@wire fetches data from Salesforce. It calls an Apex method or a Lightning Data Service adapter such as getRecord, and gives you automatic refresh, reactive updates when a parameter changes, and better performance when the Apex method is cacheable=true.

import getAccounts from '@salesforce/apex/AccountController.getAccounts';

@wire(getAccounts, { industry: '$selectedIndustry' })
accounts;

Use case: loading account records when the component renders, and refetching whenever selectedIndustry changes.

10. Best practices for LWC

  • Use Lightning Data Service wherever possible, so record access, sharing and caching are handled for you.
  • Avoid unnecessary Apex calls.
  • Mark read-only Apex methods cacheable=true.
  • Break large components into smaller reusable ones.
  • Handle errors rather than letting a rejected promise fail silently.
  • Avoid heavy DOM manipulation. Let the template render from state.

11. Error handling in LWC

Handle it at all three layers, and saying so marks the answer as coming from real work.

Apex layer. Use try and catch, and throw an AuraHandledException with a message the user can act on instead of letting a raw stack trace reach the browser.

try {
    return OrderService.createOrder(accountId);
} catch (Exception e) {
    throw new AuraHandledException('Order could not be created: ' + e.getMessage());
}

JavaScript layer. Handle promise failures in a .catch() block, and store the error so the template can react.

UI layer. Fire a ShowToastEvent so the failure is visible to the user, not only logged.

12. Best practices for Triggers

  • One trigger per object. Multiple triggers have no guaranteed execution order, which creates conflicts that are painful to debug.
  • Use a trigger handler pattern. Trigger to handler class to service layer. The trigger holds no logic, only routing by context.
  • Bulkify. Write for 200 records. No SOQL and no DML inside a loop.
  • Avoid recursion. A static boolean stops the trigger re-entering itself after an update.
  • Separation of concerns. Business logic lives in classes, not the trigger body.
trigger AccountTrigger on Account (before insert, after update) {
    if (Trigger.isBefore && Trigger.isInsert) {
        AccountTriggerHandler.beforeInsert(Trigger.new);
    }
    if (Trigger.isAfter && Trigger.isUpdate) {
        AccountTriggerHandler.afterUpdate(Trigger.new, Trigger.oldMap);
    }
}

13. Before doing any integration what all things will you keep in mind and what will be the approach

Go through this as a checklist, because that is how it is being scored.

Area What you settle before writing code
Authentication OAuth, API keys or JWT, and where credentials are stored
Security HTTPS for transmission, and whether any field needs encryption at rest
Data mapping Which Salesforce field maps to which external field, and who owns that document
Error handling Retry strategy, fallback process, what happens to a permanently failed record
Governor limits Callout limits per transaction, and whether volume forces asynchronous processing
Logging An integration log object holding request, response and status so failures are traceable

Logging and retry get built before go-live, not after the first production failure.

14. What are record triggered flows

Record triggered flows run automatically on create, on update and on delete, in one of two positions.

Before save flow runs before the record is written. Used for fast field updates on the same record, because it sets the value in memory with no extra DML.

After save flow runs after the record is committed. Used when related records need to be created or updated, or when you need the record Id.

These replaced Workflow Rules and Process Builder, both retired for new automation.

15. What is mixed DML error? How this can be fixed.

A mixed DML error occurs when you perform DML on a setup object and a non-setup object in the same transaction. User, UserRole, Group, GroupMember and Permission Set Assignment are setup objects. Account, Contact, Opportunity and custom objects are not. Insert a User and an Account together and Salesforce throws the error.

The fix is to split the operations across transactions using asynchronous processing, a @future method, or Queueable Apex when you need chaining.

@future
public static void assignPermissionSet(Id userId, Id permSetId) {
    insert new PermissionSetAssignment(
        AssigneeId = userId, PermissionSetId = permSetId
    );
}

In test classes the same problem is solved with System.runAs(). Add that, because it is the usual follow-up.

16. How to prevent mixed DML error in record triggered flows

Same principle. Separate the transactions.

  • Use the asynchronous path in the flow. A scheduled path running immediately after the transaction puts the setup object DML in its own transaction.
  • Use Platform Events. Publishing an event creates a separate transaction, and a subscriber does the setup object work there.
  • Use asynchronous Apex. Call an invocable action that hands the work to Queueable or a @future method.

What the interviewer is actually checking in L1

  • Whether you have deployed, not just coded. Questions 5 and 6 both reduce to the difference between a sandbox and production, and that gap only exists in the mind of someone who has shipped.
  • Whether you know when code runs, where it runs and what data it can reach. Batch Apex syntax is not the same as knowing that start() and each execute() are separate transactions with separate limits.
  • Whether your project experience is real. Integration and POC come first so the interviewer can return to your answers later and go deeper.
  • Whether you can debug. "Coverage is 0%, why" is a debugging question in a coverage costume. Answer it as a diagnosis with an order of checks.

L2 Round (Techno-Managerial)

1. Query to show opportunity record with 3rd highest amount

Sort descending and skip the first two records with OFFSET.

SELECT Id, Name, Amount
FROM Opportunity
WHERE Amount != NULL
ORDER BY Amount DESC
LIMIT 1
OFFSET 2

The null filter matters, because nulls in the sort order give you the wrong row. OFFSET in SOQL is capped at 2000, so this works for third highest but not for deep pagination.

2. Explain all integrations that have you worked on

The same question as L1 question 1, asked by a different interviewer. The repetition is deliberate. They are checking whether the story holds up twice.

In L2 the answer is pitched at design level. Cover the type of integration and direction of data, the authentication used, the architecture including whether middleware sits in between and why, the error handling strategy, and the logging mechanism.

Say why you chose REST over middleware, or why the callout had to be asynchronous. Structure it as situation, approach, reason, result. Candidates who open with "actually sir basically in our project we had one requirement" lose the room in ten seconds.

3. In LWC, @wire methods sometimes get called unnecessarily multiple times during navigation. How do you prevent or control unnecessary execution of wire methods?

Wire methods are reactive. Every time a reactive parameter changes, the wire runs again. During navigation the component can be re-instantiated or its parameters reassigned, so it fires more often than the user action warranted.

  • Reduce reactive parameters. Every $property in the wire configuration is a trigger.
  • Use imperative Apex instead. Call the method from a handler when you actually need the data.
import getAccounts from '@salesforce/apex/AccountController.getAccounts';

handleSearch() {
    getAccounts({ industry: this.selectedIndustry })
        .then(result => { this.accounts = result; })
        .catch(error => { this.error = error; });
}
  • Mark the Apex method cacheable=true. Repeat calls then come from the client cache rather than the server.

If pushed further, add that a null or undefined reactive parameter still fires the wire with that value, so guarding inside the Apex method is worth doing.

4. While running a batch job we are getting too many query rows: 50001, how to prevent it and why it is coming

Asked again in L2, this time as a design question rather than a debugging one. Rows retrieved by SOQL exceed the governor limit of 50,000 in a single transaction, driven by large production data volume and a query that lacks filtering.

Prevention: use Database.QueryLocator in start(), since the records it returns do not count toward the limit, apply filtering on an indexed field, reduce unnecessary queries, and scope every child query to the records being processed.

For L2, add the design layer. The real prevention is sizing the query against production volume at design time and load-testing the batch in a full copy sandbox before release, instead of finding the limit on go-live night.

5. There is a list of records on parent component, in child component that list is updated. How parent component will get updated.

The child fires a custom event after updating the records, the parent listens and refreshes its data. The child never mutates the parent's list directly.

// child.js, after the save completes
this.dispatchEvent(new CustomEvent('recordsupdated'));

// parent.js
import { refreshApex } from '@salesforce/apex';
handleRecordsUpdated() {
    return refreshApex(this.wiredAccountsResult);
}

Name refreshApex explicitly. It is what makes the parent's wired data reload from the server rather than serving the stale cached copy.

6. Tell the approach for integrating Payment service. How would you design it and what all best practices you will use. (By best practices he meant all integration, triggers, classes best practices)

The closing question pulls together everything before it. Answer it as an architecture walkthrough.

Authentication. OAuth or token based, with no credential hardcoded in Apex.

Named Credentials. Store endpoint and authentication configuration there, so the same code runs in sandbox and production against different endpoints.

Integration layer design. Controller layer for the entry point, service layer for business logic, utility layer for callout mechanics and JSON parsing.

Error handling. Retry logic for transient failures, meaningful messages for permanent ones. Decide in advance which HTTP status codes are retryable.

Logging. An Integration Log custom object storing request, response, status code and the related record. When a payment fails at 2 am, it is the only thing that tells you what happened.

Security. Encrypt sensitive payment data, and keep card data out of Salesforce where the design allows, holding a gateway token instead.

Asynchronous processing. Queueable Apex for the callout, so the user transaction is not blocked and the callout is not attempted from a trigger context that has already done DML.

Trigger and class practices carry over. One trigger per object, logic in the handler, bulkified code, no SOQL in loops, and a test class that mocks the callout with HttpCalloutMock.

What the interviewer is actually checking in L2

  • Whether you think in design terms. The integration question from L1 is now scored on architecture, not syntax.
  • Whether you can defend your resume under repetition. Questions 2 and 4 are repeats for exactly this reason.
  • Whether you answer in a structure. Situation, approach, reason, result beats a rambling recollection.
  • Whether you have seen production. The payment question rewards anyone who mentions logging, retry and mocking, because those get built after being burned.
  • Whether you can say "I have not done that". L2 interviewers respect a clean boundary more than a bluff they can unpick in two follow-ups.

Preparing for this kind of round

Most candidates who fail these rounds know the material. What they cannot do is demonstrate it. They can define a trigger handler pattern but cannot describe the bug that made their team adopt one. They can explain Batch Apex but have never watched one fail at 50,001 rows during a Saturday deployment.

The fix is building and breaking things in your own org, then practising the explanation aloud until it comes out as situation, approach, reason, result. That is how our Salesforce training in Pune with placement support is structured, with real project work and mock rounds run the way KPMG and similar firms run theirs.

Work through these 22 questions by answering them aloud before reading the answer again. Any answer you cannot get through without stopping is the topic to go and build.