Skip to main content

SF-0262 · Concept · Medium

How does apex work?

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

Apex doesn’t run on your machine, and it doesn’t run as plain text on Salesforce’s servers either. When you save an Apex class, the platform compiles your source into a low-level set of instructions that the multi-tenant runtime then executes inside a heavily monitored sandbox. That compilation, storage, and execution model is what makes Apex possible in a shared-tenancy environment.

The lifecycle of an Apex request

  1. Authoring — you write Apex in Developer Console, VS Code with the Salesforce extension, or the Setup UI.
  2. Compilation — on save (or on deploy), the platform parses the source, validates references against the org’s metadata, and compiles it to an abstract set of instructions stored in the Apex metadata.
  3. Storage — the compiled form lives alongside other metadata in the org. There’s no “production server” you push a binary to; the metadata is the artifact.
  4. Invocation — something triggers the code: a DML on a triggered object, a user clicking a button that calls a controller method, an @invocableMethod called from Flow, a scheduled job firing, an inbound REST request.
  5. Execution — the Apex runtime loads the compiled instructions and runs them inside a transaction with a metered context.
  6. Commit or rollback — when the entry-point method returns, the platform commits the DML; if an unhandled exception escapes, everything inside the savepoint rolls back.

What “multi-tenant” means for your code

Your Apex shares CPU, memory, and database resources with every other org running on the same pod. To prevent one tenant’s bad code from starving everyone else, the runtime meters every operation:

  • SOQL queries per transaction (synchronous: 100, async: 200)
  • DML statements per transaction (150)
  • CPU time per transaction (10,000 ms synchronous, 60,000 ms async)
  • Heap size (6 MB synchronous, 12 MB async)
  • Records returned by SOQL (50,000)
  • Callouts per transaction (100)

These are the famous governor limits. The runtime checks them on every metered operation and throws a LimitException the moment one is exceeded. There is no quota system, no “try again later” — the transaction dies and rolls back.

Transaction boundaries

Each Apex entry point — a trigger fire, a controller call, a future job, a queueable execute — is its own transaction with its own fresh set of limit counters. This is why chaining is sometimes the right answer: when one transaction can’t fit the work, split it into a Queueable that enqueues another Queueable, each with its own quota.

public class AccountRefresher implements Queueable, Database.AllowsCallouts {
    public void execute(QueueableContext qc) {
        // This Queueable gets its own 200-SOQL, 60-second CPU budget
        List<Account> accounts = [SELECT Id, Name FROM Account LIMIT 200];
        // ... do work ...
        update accounts;
        // Chain to another Queueable if more work remains
        if (Limits.getQueueableJobs() < Limits.getLimitQueueableJobs()) {
            System.enqueueJob(new AccountRefresher());
        }
    }
}

Compile-time vs runtime checking

Apex is strongly typed, and most reference errors are caught at compile time:

  • Referencing a non-existent SObject field in a SOQL query is a compile error.
  • Calling a method with the wrong type signature is a compile error.
  • Forgetting @isTest on a test class is a compile error.

But some checks only happen at runtime:

  • Sharing and FLSwith sharing enforces record sharing at query time, not compile time.
  • Governor limits — counted as you execute, not statically analyzed.
  • Dynamic SOQLDatabase.query(string) is unchecked at compile time. Bind variables in the string can cause injection if you build it from user input.

What interviewers are really looking for

When this question comes up, the interviewer wants to hear that you understand Apex is constrained by design, not by accident. Drop the words multi-tenant, metered runtime, governor limits, and transaction-scoped and you’ve shown the depth they’re testing for. Bonus points for mentioning that compiled Apex is stored as metadata — that’s a fact many developers never internalize.

Verified against: Apex Developer Guide — Understanding Apex Core Concepts, Execution Governors and Limits. Last reviewed 2026-05-17 for Spring ‘26 release.