7.2 SOSL Search Fundamentals

Key Takeaways

  • SOSL uses FIND 'term' IN SearchGroup RETURNING Object(fields…), Object2(fields…) to search text across one or more objects
  • Choose SOSL for free-text / keyword search across objects; choose SOQL for structured filters, relationships, and aggregates on known objects
  • SearchGroup options include ALL FIELDS, NAME FIELDS, EMAIL FIELDS, PHONE FIELDS, and SIDEBAR FIELDS
  • Apex SOSL returns List<List<SObject>>; each inner list matches a RETURNING object in order—cast elements to the concrete type
  • SOSL has its own governor and result limits; wildcards and short tokens behave differently than SOQL LIKE filters
Last updated: August 2026

7.2 SOSL Search Fundamentals

Quick Answer: SOSL (Salesforce Object Search Language) finds records by text search across one or more objects with FIND … IN … RETURNING …. Use SOSL when users type keywords and you do not know which object or field holds the match. Use SOQL when you filter structured data (IDs, picklists, amounts, exact relationships). In Apex, SOSL returns List<List<SObject>>—one list per RETURNING target.

Platform Developer I expects you to pick the right query language and to read SOSL results without off-by-one casting mistakes. Many “global search box” and “find this phone/email somewhere” scenarios map to SOSL.

FIND … IN … RETURNING Syntax

Core shape:

String term = 'Acme';
List<List<SObject>> searchResults = [
    FIND :term
    IN ALL FIELDS
    RETURNING
        Account(Id, Name, Industry WHERE Industry != null ORDER BY Name LIMIT 20),
        Contact(Id, FirstName, LastName, Email),
        Lead(Id, Name, Company)
];
PieceMeaning
FINDSearch term (string or bind). Quotes/syntax rules differ slightly between Apex inline SOSL and API forms—follow Apex bind style in code.
IN SearchGroupWhich field categories participate (ALL FIELDS, NAME FIELDS, etc.).
RETURNINGObjects to return, each with its own field list and optional WHERE / ORDER BY / LIMIT.

Optional clauses on each RETURNING object refine results after the text match—for example, only Accounts in a certain Industry, or a LIMIT so one object cannot dominate the payload.

Binding the search term

String userInput = 'acme.com';
List<List<SObject>> hits = [
    FIND :userInput IN EMAIL FIELDS
    RETURNING Contact(Id, Email), Lead(Id, Email)
];

Bind variables keep dynamic terms clean. SOSL still has rules about reserved characters and minimum token length; very short strings may return no rows. Leading wildcards are limited compared with casual “%anything%” thinking from SQL.

When SOSL vs SOQL

NeedPrefer
Keyword / free-text across multiple objectsSOSL
Search Name, Email, Phone-like fields like global searchSOSL
Filter by Amount, Stage, custom number, exact Id setSOQL
Parent-child relationship queries and aggregatesSOQL
Know the object and structured WHERE is enoughSOQL (usually faster and clearer)
“Find records mentioning X somewhere in text”SOSL

Exam decision frame: If the prompt says the user types a string into a search box and results may include Accounts, Contacts, and Leads, SOSL is the tool. If the prompt says “all Opportunities with Stage = Closed Won and Amount > 50000,” that is SOQL—not SOSL.

SOSL is not a replacement for relationship traversal. You cannot express “Contacts whose Account Industry is Healthcare” as cleanly as SOQL; you search text, then optionally filter RETURNING rows, or follow up with SOQL on IDs.

SearchGroup Options

The IN clause narrows which field groups are searched:

SearchGroupTypical fields covered (conceptually)
ALL FIELDSBroadest text search across searchable fields
NAME FIELDSName-oriented fields (useful for people/company name search)
EMAIL FIELDSEmail-type fields
PHONE FIELDSPhone-type fields
SIDEBAR FIELDSFields used in sidebar / limited search UI behavior
// Narrow: only phone-like fields
List<List<SObject>> phoneHits = [
    FIND '415*' IN PHONE FIELDS
    RETURNING Contact(Id, Phone, MobilePhone), Account(Id, Phone)
];

Exam tip: Matching SearchGroup to the requirement shows intent. Searching emails with IN PHONE FIELDS is wrong even if syntax is legal. Prefer the narrowest group that satisfies the requirement when the question emphasizes efficiency or precision.

Returned Structure: List of Lists

Apex assigns SOSL results to List<List<SObject>>. Order of inner lists matches RETURNING order:

List<List<SObject>> raw = [
    FIND 'Acme' IN NAME FIELDS
    RETURNING Account(Id, Name), Contact(Id, LastName), Lead(Id, Name)
];

List<Account> accounts = (List<Account>)raw[0];
List<Contact> contacts = (List<Contact>)raw[1];
List<Lead> leads = (List<Lead>)raw[2];

for (Account a : accounts) {
    System.debug(a.Name);
}

Common bugs:

  1. Treating raw as List<Account> — wrong type.
  2. Off-by-one index after reordering RETURNING objects.
  3. Forgetting empty inner lists are valid (no matches for that object).
  4. Accessing fields not included in that object’s RETURNING field list.

Dynamic SOSL uses Search.query with a string and the same list-of-lists result shape. Prefer static SOSL when the shape is fixed so the compiler helps.

Filters, ORDER BY, and LIMIT on RETURNING Objects

Each target can carry SOQL-like clauses:

List<List<SObject>> filtered = [
    FIND 'renewal' IN ALL FIELDS
    RETURNING
        Opportunity(
            Id, Name, StageName, Amount
            WHERE StageName != 'Closed Lost'
            ORDER BY Amount DESC
            LIMIT 25
        ),
        Case(Id, Subject, Status LIMIT 25)
];

Use these to keep payloads exam- and production-friendly. Overall SOSL still returns only records that matched the FIND text (subject to indexing/searchability); WHERE further restricts that set.

Limits and Operational Awareness

Candidates should remember conceptual SOSL constraints (verify exact numbers in the current Apex Developer Guide if Salesforce revises them):

  • Per-transaction SOSL query counts are limited (historically a small number such as 20 SOSL queries per synchronous transaction—far fewer than SOQL’s 100).
  • Each SOSL search returns a maximum number of rows overall (commonly discussed as 2,000 rows across returned objects—confirm current docs).
  • Search indexes may lag slightly after DML; brand-new records might not appear instantly in SOSL the way they do in SOQL in the same transaction in every scenario—design UIs accordingly.
  • Not every field is searchable; encrypted, some formula, and non-indexed text behaviors can exclude matches.

Bulkification still applies: Do not run SOSL inside a per-record loop. One search for a term (or carefully designed dynamic searches) is the pattern; never for (Contact c : Trigger.new) { FIND … }.

SOSL Anti-Patterns on the Exam

Anti-patternBetter approach
SOSL to load records by Id setSOQL WHERE Id IN :ids
SOSL for SUM/COUNT of AmountSOQL aggregate
Building FIND strings with unescaped user punctuation carelesslyBind variables; validate input
Ignoring list-of-lists castingIndex and cast each RETURNING object
Assuming SOSL sees uncommitted DML alwaysRe-query with SOQL when same-transaction consistency matters

End-to-End Example: Omnibox Search Service

public with sharing class GlobalFind {
    public class Result {
        public List<Account> accounts;
        public List<Contact> contacts;
    }

    public static Result search(String term) {
        Result r = new Result();
        if (String.isBlank(term) || term.length() < 2) {
            r.accounts = new List<Account>();
            r.contacts = new List<Contact>();
            return r;
        }
        List<List<SObject>> raw = [
            FIND :term IN ALL FIELDS
            RETURNING
                Account(Id, Name ORDER BY Name LIMIT 50),
                Contact(Id, Name, Email ORDER BY LastName LIMIT 50)
        ];
        r.accounts = (List<Account>)raw[0];
        r.contacts = (List<Contact>)raw[1];
        return r;
    }
}

This pattern shows with sharing, bind FIND, dual RETURNING, LIMIT, and correct casting—the cluster of ideas exams combine in one scenario.

Putting It Together for the Exam

Ask on every search question:

  1. Free text across objects → SOSL; structured single-object filter → SOQL.
  2. Is the SearchGroup aligned with emails, phones, names, or all fields?
  3. Do I unpack List<List<SObject>> in RETURNING order?
  4. Did I avoid SOSL-in-a-loop and respect SOSL’s tighter query count?

Section 7.3 connects search/query results to DML changes; section 7.4 places both under governor ceilings.

Test Your Knowledge

A Lightning page must let users type a keyword and return matching Accounts, Contacts, and Leads in one operation. Which approach fits best?

A
B
C
D
Test Your Knowledge

In Apex, what is the result type of an inline SOSL query that returns Accounts and Contacts?

A
B
C
D
Test Your Knowledge

When should a developer choose SOQL instead of SOSL?

A
B
C
D