Back to All Cheatsheet Libraries cheatsheets

Salesforce

Core objects, automation tools, and platform reference for Salesforce.

Salesforce is a multi-tenant platform with governor limits

Everything unusual about Salesforce follows from one fact: your org shares infrastructure with thousands of others. That's why there are hard runtime caps on queries, records processed, and CPU time — governor limits — and why code that would be fine anywhere else fails here.

The second thing to internalise is that configuration beats code. A great deal of what you'd write an application for is a checkbox, a formula field, or a Flow. Reaching for Apex first is the most common expensive mistake.

Object Represents Notes
AccountA company or organisation.The hub most other records hang off. Person Accounts are a separate, hard-to-reverse setting.
ContactA person, usually linked to an Account.Contact-to-multiple-accounts exists but is off by default.
LeadAn unqualified prospect.Converts into Account + Contact + optional Opportunity. Conversion is effectively one-way.
OpportunityA potential deal, with an amount, stage, and close date.Drives forecasting. Stage changes are what most reporting is built on.
CaseA support request.Core of Service Cloud. Has its own assignment and escalation rules.
CampaignA marketing effort.Campaign Members link it to Leads and Contacts for attribution.
Task / EventActivities — calls, emails, meetings.Both are Activity records underneath, which makes reporting on them quirky.
Custom objectAnything you define.API name always ends __c. Managed-package objects carry a namespace prefix.
Relationships
  • Lookup — a loose reference. The child survives if the parent is deleted, and it has its own sharing.
  • Master-detail — a tight ownership link. Deleting the parent deletes the children, the child inherits the parent's sharing and has no owner of its own, and it enables roll-up summary fields.
  • Converting master-detail to lookup is possible only if no roll-ups exist, and going the other way requires every child to have a parent. Choose deliberately.
  • Junction object — a custom object with two master-detail fields, the standard many-to-many pattern.
  • Roll-up summary fields (COUNT, SUM, MIN, MAX) work only over master-detail. For lookups you need a Flow, Apex, or a tool like DLRS.
  • A record's 15-character ID is case-sensitive; the 18-character version is not. Always use the 18-character form in integrations.
Security, in the order it applies
  • 1. Object — profiles and permission sets grant Create/Read/Edit/Delete per object.
  • 2. Field — field-level security can hide a field even on a readable object.
  • 3. Record — org-wide defaults, then role hierarchy, sharing rules, and manual shares open access up from there.
  • Org-wide defaults are the floor: set them Private and open selectively, rather than starting open.
  • Use permission sets, not profiles. A user has one profile but many permission sets — that's how you avoid a profile per person.
  • Apex runs in system mode by default, ignoring all of the above. with sharing and WITH USER_MODE are how you respect it — see the Apex tab.

SOQL is not SQL

No SELECT *, no arbitrary joins, no UNION. You traverse relationships instead of joining tables, and you must name every field you want. Run queries in Developer Console's Query Editor or via the CLI.

-- Every field must be named. There is no SELECT *. SELECT Id, Name, StageName, Amount, CloseDate FROM Opportunity WHERE StageName = 'Closed Won' AND CloseDate = THIS_QUARTER ORDER BY Amount DESC LIMIT 100 -- Parent traversal: dot-walk UP through a lookup (max 5 levels) SELECT Id, Name, Account.Name, Account.Owner.Email FROM Contact WHERE Account.Industry = 'Technology' -- Child subquery: traverse DOWN using the relationship name (max 1 level) SELECT Id, Name, (SELECT Id, Subject, Status FROM Cases WHERE Status != 'Closed') FROM Account WHERE BillingCountry = 'United Kingdom' -- Custom relationships use __r for the relationship, __c for the field SELECT Id, Custom_Field__c, Parent_Object__r.Name FROM My_Object__c -- Date literals — use these rather than hardcoded dates WHERE CreatedDate = LAST_N_DAYS:30 WHERE CloseDate = THIS_FISCAL_QUARTER WHERE LastModifiedDate = YESTERDAY -- Aggregates. Anything not aggregated must be in GROUP BY. SELECT StageName, COUNT(Id) total, SUM(Amount) value FROM Opportunity GROUP BY StageName HAVING SUM(Amount) > 100000 -- Semi-join / anti-join SELECT Id FROM Account WHERE Id IN (SELECT AccountId FROM Opportunity) SELECT Id FROM Account WHERE Id NOT IN (SELECT AccountId FROM Case) -- Recover deleted records (within the ~15-day recycle bin window) SELECT Id, Name FROM Account WHERE IsDeleted = true ALL ROWS -- FOR UPDATE locks rows for the transaction SELECT Id FROM Account WHERE Id = :accId FOR UPDATE -- SOSL: text search ACROSS objects, which SOQL cannot do FIND {Acme*} IN ALL FIELDS RETURNING Account(Id, Name), Contact(Id, Name, Email), Lead(Id, Company)
Group Syntax Notes
TraversalAccount.Owner.NameUp through lookups. Five levels maximum.
Traversal(SELECT ... FROM Contacts)Down to children. Only one level. Plural relationship name.
TraversalParent__r.Field__cCustom relationships end __r, custom fields __c.
DatesTODAY, YESTERDAY, THIS_WEEKUnquoted literals — quoting them breaks the query.
DatesLAST_N_DAYS:30Also NEXT_N_QUARTERS:n, LAST_N_FISCAL_YEARS:n.
FilterLIKE 'Acme%'% and _ wildcards, on text fields only.
FilterINCLUDES ('A';'B')Multi-select picklists. Semicolon means AND, comma means OR.
Filter:variableApex bind variable. Always bind rather than concatenating — SOQL injection is real.
SpecialALL ROWSIncludes soft-deleted and archived records.
SpecialFOR UPDATERow locking. Overuse causes lock contention errors.
SpecialWITH USER_MODEEnforces FLS and sharing on the query. Prefer this in new Apex.
SearchFIND {term} RETURNING ...SOSL — the only way to text-search several objects at once.

Flow is the automation tool now

Workflow Rules and Process Builder are retired — Salesforce ended support and provides a migration tool. Anything you build today should be a Flow, and inherited orgs usually need a migration project.

The order automation fires in matters enormously, because a later step can overwrite an earlier one and it's rarely obvious why a field "won't stay set".

1

Know the order of execution

Roughly: validation rules → before triggers → before-save Flows → save to database (not committed) → after triggers → after-save Flows → assignment/auto-response/workflow rules → escalation → roll-up summaries → commit.

Two automations touching the same field in different phases is the usual cause of a value that reverts.

2

Pick the right Flow type

Record-Triggered for reacting to a change — and prefer before-save when you're only setting fields on the same record, since it's dramatically faster and consumes no DML.

Screen Flow for guided user input. Scheduled for batch work. Autolaunched to be called from elsewhere.

3

One record-triggered Flow per object per timing

Several Flows on the same object and timing run in an unpredictable order. Consolidate into one with branching logic, or you'll be debugging race conditions.

4

Never put a DML or query element inside a loop

This is the number one Flow mistake and it hits governor limits the moment someone does a bulk import. Collect records into a variable inside the loop, then do a single Update after it.

5

Set fault paths

An unhandled Flow error shows the user an unhelpful message and emails the admin. Add a fault connector on every DML element with a real message.

6

Test with bulk data before deploying

A Flow that works on one record can fail on 200. Load a batch in a sandbox — that's the test that matters.

Configuration before code
  • Formula field — calculated on read, always current, no storage. First choice for derived values.
  • Roll-up summary — aggregate over master-detail children with no code.
  • Validation rule — blocks a save when the formula evaluates true. Note it fires on every save path, including integrations and data loads.
  • Duplicate and matching rules — deduplication without a managed package.
  • Custom Metadata Types — configuration that deploys between orgs, unlike Custom Settings data. Use these for anything a developer would otherwise hardcode.
  • Only reach for Apex when the platform genuinely can't express it. Declarative config is upgraded by Salesforce; your Apex is your problem forever.

Bulkification is not optional

Apex triggers receive up to 200 records at a time. Code written as though it handles one record will hit a governor limit and throw on the first real data load. This single pattern accounts for most production Apex failures.

// WRONG — a query and a DML inside a loop. // 200 records = 200 queries = limit exceeded, transaction fails. for (Account a : Trigger.new) { List<Contact> cs = [SELECT Id FROM Contact WHERE AccountId = :a.Id]; for (Contact c : cs) { c.Description = 'x'; update c; } } // RIGHT — one query, one DML, regardless of batch size. Set<Id> accountIds = Trigger.newMap.keySet(); List<Contact> toUpdate = new List<Contact>(); for (Contact c : [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accountIds WITH USER_MODE]) { c.Description = 'x'; toUpdate.add(c); } if (!toUpdate.isEmpty()) { update toUpdate; } // One trigger per object, delegating to a handler class. trigger AccountTrigger on Account (before insert, before update, after insert, after update) { new AccountTriggerHandler().run(); } // Partial success — process what you can, collect the failures. Database.SaveResult[] results = Database.update(toUpdate, false); for (Database.SaveResult r : results) { if (!r.isSuccess()) { System.debug(r.getErrors()[0].getMessage()); } }
Governor limit Synchronous Notes
SOQL queries100200 in async. The limit a loop-query blows first.
Records returned by SOQL50,000Use a query loop or Batch Apex beyond this.
DML statements150Counts statements, not records — one update of 10,000 records is a single DML.
Records per DML10,000Per transaction.
CPU time10,000 ms60,000 ms async. Excludes database and callout wait time.
Heap size6 MB12 MB async. Large collections hit this.
Callouts100120 s total. No callouts after DML in the same transaction without @future or Queueable.
Trigger batch size200Why bulkification matters.
Test coverage to deploy75%Org-wide, and every trigger needs some coverage.
# Salesforce CLI (sf) — the modern replacement for sfdx sf org login web --alias dev --set-default sf org list sf org open --target-org dev # Query from the terminal sf data query --query "SELECT Id, Name FROM Account LIMIT 10" sf data query --query "SELECT Id FROM Contact" --result-format csv > out.csv # Bulk data sf data import bulk --file accounts.csv --sobject Account sf data export bulk --query "SELECT Id, Name FROM Account" --output-dir ./out # Metadata sf project retrieve start --metadata ApexClass sf project deploy start --source-dir force-app --dry-run sf project deploy start --source-dir force-app --test-level RunLocalTests # Apex sf apex run --file script.apex sf apex test run --code-coverage --result-format human --wait 10 sf apex tail log --color # Scratch orgs sf org create scratch --definition-file config/project-scratch-def.json \ --alias scratch1 --duration-days 7

Gotchas

Apex ignores your security model by default
  • Apex runs in system mode — it ignores object permissions, field-level security, and sharing rules unless you say otherwise.
  • with sharing on the class enforces record-level sharing. It does not enforce object or field permissions.
  • WITH USER_MODE on a query (and as user on DML) enforces FLS, object permissions, and sharing together. This is the modern answer — prefer it in new code.
  • inherited sharing takes the caller's context — the right default for a utility class.
  • A class with no sharing declaration defaults to without sharing in many contexts. Be explicit, always.
  • This is the most common source of real Salesforce security findings. Exposing an Apex method to Lightning or a Site without user-mode enforcement leaks data across accounts.
Things that catch people
  • Lead conversion is effectively one-way. There's no supported unconvert; you're restoring from a backup or rebuilding by hand.
  • Deleting a field is a two-stage process. It sits in a recycle bin for 15 days before permanent erasure, and its data is gone when it goes.
  • You cannot reduce a text field's length or change certain field types once data exists — some changes require a new field and a migration.
  • Validation rules fire on every save path, including data loads and integrations. A well-meant rule can break a nightly sync.
  • Formula fields are recalculated on read and count toward query performance; deeply nested ones on large objects cause real slowness.
  • Changing an org-wide default is asynchronous and can take hours on a large org while sharing recalculates.
  • Sandboxes refresh on a schedule — Full copy every 29 days, Partial every 5, Developer daily. Plan around it.
  • Test classes don't see org data unless annotated @isTest(SeeAllData=true), which you should avoid. Create your own test data.
  • Salesforce force-upgrades all orgs three times a year (Spring, Summer, Winter). Read the release notes; things do change.

Tips

Login as a user

Setup → Users → Login. The only reliable way to answer "why can't they see this record" — permission theory rarely matches reality.

Debug logs, filtered

Setup → Debug Logs, or sf apex tail log. Set the Apex level to FINEST and the rest to NONE, or the useful lines drown in noise.

Anonymous Apex for one-offs

Developer Console → Execute Anonymous, or sf apex run. Perfect for a data fix. Wrap risky work in a rollback to preview: Savepoint sp = Database.setSavepoint(); ... Database.rollback(sp);

Watch your limits at runtime

Limits.getQueries() and Limits.getLimitQueries() tell you how close you are. Log them in complex transactions before they fail in production.

Custom Metadata over Custom Settings

Custom Metadata records deploy between orgs as metadata; Custom Settings data doesn't. Anything a developer might hardcode belongs here instead.

Trailhead is genuinely good

Free, hands-on, with a real practice org attached. Unusually, the vendor's own training is the best available resource for this platform.

Resources