Skip to main content

SF-0287 · Concept · Medium

What is dynamic SOSL?

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

Dynamic SOSL is a Salesforce Object Search Language statement constructed as a string at runtime and executed with Search.query(). It’s the SOSL counterpart to dynamic SOQL: instead of writing a static [FIND 'Acme' IN ALL FIELDS RETURNING Account, Contact], you build the search term, the field scope, and the returning clause from variables.

Static vs dynamic SOSL

// Static — compiled and bound at deploy time
List<List<SObject>> results = [
    FIND 'Acme' IN ALL FIELDS
    RETURNING Account(Id, Name), Contact(Id, Email)
];

// Dynamic — built and bound at runtime
String term = 'Acme';
String search = 'FIND \'' + String.escapeSingleQuotes(term) + '\'' +
                ' IN ALL FIELDS' +
                ' RETURNING Account(Id, Name), Contact(Id, Email)';

List<List<SObject>> results = Search.query(search);

Search.query() always returns a List<List<SObject>> — one inner list per object in the RETURNING clause, in the order you listed them.

When to use SOSL at all

Reach for SOSL — static or dynamic — when:

  • You need to search across multiple objects in one call.
  • You’re matching against full-text indexed fields (Name, Text, Long Text Area, Email, Phone, etc.) and want the platform’s search engine — fuzzy matching, stemming, synonyms — instead of LIKE.
  • The search term spans the org-wide global search box experience.

SOSL is slower than a targeted SOQL with a LIKE on an indexed field for a single object. For one-object lookups, SOQL almost always wins. For “find anything that mentions Acme across Accounts, Contacts, and Cases” — SOSL is the tool.

Dynamic SOSL injection

Same problem as SOQL: concatenating user input is a vulnerability.

// VULNERABLE
String search = 'FIND \'' + userInput + '\' IN ALL FIELDS RETURNING Account(Id)';
List<List<SObject>> r = Search.query(search);

Defenses, in order of preference:

  1. String.escapeSingleQuotes(input) — the primary defense for the FIND term itself.
  2. Bind variables — SOSL bind support arrived later than SOQL’s; the API is Search.find() with bind syntax, and many shops still escape manually.
  3. Validate object and field names against Schema.getGlobalDescribe() — they can’t be parameterised, so they must be checked.
public static Map<String, List<SObject>> findAll(String term,
                                                 List<String> objectNames,
                                                 Map<String, List<String>> fieldsByObject) {

    String safeTerm = String.escapeSingleQuotes(term);
    List<String> returning = new List<String>();
    for (String obj : objectNames) {
        List<String> fields = fieldsByObject.get(obj);
        returning.add(obj + '(' + String.join(fields, ', ') + ')');
    }

    String search = 'FIND \'' + safeTerm + '*\'' +
                    ' IN ALL FIELDS' +
                    ' RETURNING ' + String.join(returning, ', ') +
                    ' LIMIT 50';

    List<List<SObject>> results = Search.query(search);

    Map<String, List<SObject>> byObject = new Map<String, List<SObject>>();
    for (Integer i = 0; i < objectNames.size(); i++) {
        byObject.put(objectNames[i], results[i]);
    }
    return byObject;
}

Note the trailing * on safeTerm — that’s SOSL’s wildcard (matches anything after the prefix). Salesforce search also supports ? for single-character wildcards.

Governor-limit angle

SOSL has its own per-transaction quota — 20 SOSL queries synchronously, 20 async. Each Search.query() call counts as one. Heavy global-search-style features should be debounced on the client and cached when possible.

What interviewers are really looking for

The basic answer names Search.query(). The senior answer covers: (1) SOSL is the right tool for cross-object full-text search, (2) dynamic SOSL has the same injection risk as dynamic SOQL and requires String.escapeSingleQuotes(), (3) it returns List<List<SObject>> in the order of the RETURNING clause, (4) the 20-query governor limit is separate from SOQL’s 100. Mention * and ? wildcards and you’ve shown end-to-end familiarity.

Verified against: SOQL/SOSL Reference — Dynamic SOSL, Search.query(). Last reviewed 2026-05-17.