Skip to main content
SFDC Developers
Apex

Apex: The Complete Guide to Salesforce's Programming Language

Vinay Vernekar · · 6 min read

Apex is the programming language behind every nontrivial Salesforce automation. This pillar links every detail-level guide on this site, organized by the questions a developer learning or working with Apex actually has.

What is Apex?

Apex is Salesforce's proprietary, strongly-typed, server-side programming language. It looks like Java, runs on Lightning Platform servers, and is the backbone of triggers, custom REST endpoints, scheduled jobs, batch processing, and any business logic too complex for Flow.

Three things make Apex distinctive:

  1. Multi-tenant governor limits. Every transaction is capped — CPU time, SOQL queries, DML statements, heap size — so one tenant's bad code can't degrade another's experience.
  2. Database-native types. sObject types map directly to Salesforce objects. Account a = new Account(Name='Acme'); insert a; — no ORM, no manual mapping.
  3. Required test coverage. 75% line coverage to deploy to production, enforced at the platform level. The discipline this forces is one of the reasons Salesforce orgs survive multi-developer teams over years.

Core concepts

Data types

Apex has five categories: primitives (Integer, Long, Double, Decimal, String, Boolean, Date, DateTime, Time, Id, Blob), collections (List, Set, Map), sObjects (Account, Contact, Custom__c), enums, and classes. Choosing the right one matters — Decimal for currency (exact), Double for math (approximate), Long only when you need values past 2 billion. Full reference: SFDC Data Types in Apex: Primitives, Collections & sObjects.

Classes and methods

public with sharing class AccountService {
  public static List<Account> getActiveByIndustry(String industry) {
    return [SELECT Id, Name FROM Account WHERE Industry = :industry AND IsActive__c = TRUE];
  }
}

with sharing / without sharing / inherited sharing controls record visibility. public / private / global controls package visibility. Most production code uses public with sharing.

Triggers

Triggers are special Apex types that run on every DML operation against an object. There are 7 trigger events organized into 2 timing categories. Full guide: Types of Apex Triggers: Before, After & 7 Trigger Events.

Async Apex

When work exceeds synchronous limits or shouldn't block the UI, Apex offers four async patterns:

Pattern When to use
Queueable Modern default — one job, full governor limits, supports chaining
Batch Apex Massive record sets — millions of rows processed in chunks
@future Legacy fire-and-forget — superseded by Queueable in most cases
Schedulable Cron-style scheduled execution

Common patterns

SOQL and DML

Apex embeds SOQL natively in square brackets:

List<Account> accs = [SELECT Id, Name FROM Account WHERE Industry = 'Tech'];
for (Account a : accs) {
  a.Name = a.Name.toUpperCase();
}
update accs;

Three rules: (1) never put DML inside a loop, (2) bulkify everything, (3) use bind variables (:myVar) instead of string concatenation. See the SOQL pillar for query depth.

String manipulation

Apex's String class has 40+ methods. The ones you'll use daily: split, join, contains, startsWith, replaceAll, format, and critically escapeSingleQuotes for dynamic SOQL injection protection. Full reference: Apex String Class: 30 Methods Salesforce Developers Use Daily.

Test classes

Every Apex class needs corresponding tests:

@isTest
private class AccountServiceTest {
  @TestSetup
  static void setup() {
    insert new Account(Name='Acme', Industry='Tech');
  }

  @isTest
  static void testGetActiveByIndustry() {
    List<Account> result = AccountService.getActiveByIndustry('Tech');
    System.assertEquals(1, result.size(), 'Expected one matching Account');
  }
}

For async testing patterns including the try/catch trap, see Apex Test Class: Catching Thrown Exceptions in Async Batch Jobs.

Governor limits cheat sheet

Resource Sync Async
SOQL queries 100 200
SOQL rows returned 50,000 50,000
DML statements 150 150
DML rows 10,000 10,000
Heap size 6 MB 12 MB
CPU time 10,000 ms 60,000 ms
Callouts 100 100
@future calls 50 50
Email recipients 5,000 / day org-wide shared

Hitting a limit throws a LimitException. The trick is designing for these — bulk-safe code, async offload, chunking — rather than trying to catch the exception after.

Deep-dive guides

When to choose Apex over Flow

Salesforce's official guidance is "configure first, code last." Use Flow when:

  • Logic fits a visual canvas (decision branches, screens, loops over collections).
  • An admin should be able to maintain it.
  • It's a CRUD-style operation: create/update related records.

Use Apex when:

  • The logic is genuinely complex (recursion, deep transformations, intricate validation).
  • You need fine-grained control over governor limits or async chaining.
  • You're building reusable libraries (utilities, integration adapters).
  • Performance matters — Apex is faster than Flow for tight loops.

The decision tree, with examples: Apex vs Flow: When to Use Code.

Common Apex mistakes

  • DML in a loop. Always batch into a List, then DML once after the loop.
  • No null check before .equals(). Use 'expected'.equals(myStr) or String.isNotBlank first.
  • Forgetting with sharing. Default Apex doesn't enforce sharing — always declare explicitly.
  • String concatenation in a loop. Use String.join for output, not +=.
  • No Test.startTest() / stopTest(). Async code in tests doesn't run without it; assertions silently pass.
  • Hardcoded IDs. Use bind variables, custom metadata, or a config class.
  • No bulk testing. A trigger that works on one record breaks at 200. Always test bulk in @isTest.

Apex is one of those languages where the syntax is easy and the discipline is hard. The deep-dive guides linked above cover the discipline — the patterns that make Apex code survive multi-year orgs and multi-developer teams. Start with data types, then triggers, then async, then testing. The other 80% you'll pick up by writing real code.

Share this article

Get weekly Salesforce dev tutorials in your inbox

Comments

Loading comments...

Leave a Comment

Trending Now