beginner
Fundamentals

SOQL vs SOSL: Which One Your Query Actually Needs

SOQL reads what you know to find. SOSL searches what you don't. Here's how to pick the right Salesforce query language every time, with Apex you can paste and run.

6 min read
Warren Walters
soql
sosl
apex
queries
beginner

TL;DR

Use SOQL when you know which object holds the data and what fields you need. Use SOSL when you have a search box and need matches across many objects in one round trip. SOQL returns one list of one object type. SOSL returns a list of lists and caps each result at 2,000 rows. If you pick wrong, you either write ten queries or write one query that fails silently.

The One-Line Difference

SOQL is a lot like SQL, but built for one object at a time:

List<Account> hot = [
    SELECT Id, Name
    FROM Account
    WHERE Rating = 'Hot'
    LIMIT 10
];

SOSL is built for search. You give it a term, a scope, and a list of objects to return. It hits them all in one call:

List<List<SObject>> found = [
    FIND 'Acme*'
    IN ALL FIELDS
    RETURNING Account(Id, Name), Contact(FirstName, LastName)
    LIMIT 10
];

That is the whole shape of the choice. One of them is a filter. The other is a search. Pick the tool that matches the question.

When SOQL Is the Right Call

Reach for SOQL when you can name the object up front. "Show me every Account in California rated Hot" is a SOQL question. "Find every Contact under Account A" is a SOQL question. "Give me the count of Opportunities by Stage" is a SOQL question.

SOQL is the workhorse for a reason. It supports everything you would expect from a query language:

  • WHERE with AND, OR, IN, LIKE
  • ORDER BY and LIMIT
  • aggregate functions like COUNT(), SUM(), AVG()
  • parent-to-child and child-to-parent traversal through relationships
  • date literals like THIS_QUARTER and LAST_N_DAYS:30

Here is a parent-to-child query that a SOQL question would naturally produce:

List<Account> withContacts = [
    SELECT Id, Name,
        (SELECT Id, LastName FROM Contacts)
    FROM Account
    WHERE Industry = 'Technology'
    LIMIT 25
];
System.debug(withContacts.size());

A SOSL query cannot do any of that. It has no WHERE Industry = 'Technology' in the strict sense, no aggregates, no parent-to-child subqueries. If your question needs those, you are writing SOQL.

When SOSL Is the Right Call

Reach for SOSL when you have a search box and you do not yet know which object the answer lives on. The classic case is a Salesforce global search bar. A user types "Acme" and expects to see Accounts, Contacts, and Opportunities that match. Three SOQL queries could do that. One SOSL query does it in a single round trip and one governor-limit count.

SOSL has its own grammar:

PartWhat it doesExample
FINDThe search term, in single quotesFIND 'Acme*'
INWhich fields to search acrossIN ALL FIELDS
RETURNINGWhich objects to return and what fieldsRETURNING Account(Name)
LIMITMax rows per object, up to 2,000LIMIT 10

Search groups are ALL FIELDS, NAME FIELDS, EMAIL FIELDS, PHONE FIELDS, and SIDEBAR FIELDS. ALL FIELDS is the default. Despite the name, it does not literally scan every column on a standard object. It scans the searchable text fields, plus name, email, phone, and sidebar fields. That is enough for almost every global-search bar.

Here is a real SOSL that searches three objects at once:

List<List<SObject>> results = [
    FIND 'Acme*'
    IN ALL FIELDS
    RETURNING
        Account(Id, Name WHERE Industry = 'Technology' LIMIT 5),
        Lead(Id, FirstName, LastName, Company LIMIT 5),
        Opportunity(Id, Name, StageName LIMIT 5)
];
for (List<SObject> row : results) {
    System.debug(row);
}

Two important things to notice. First, the result is List<List<SObject>>. The outer list has one entry per object you named in RETURNING. The inner list is the records for that object. You almost always loop the outer list and cast each inner list to the type you expect.

Second, each object can have its own WHERE, ORDER BY, and LIMIT. SOSL filters per object, not across the whole result. That is how you keep a search bar from returning 2,000 of one object and zero of the rest.

The Limits That Bite

SOQL and SOSL have different ceilings, and forgetting which is which is the fastest way to hit a governor limit.

CapSOQLSOSL
Max rows returned50,000 per query2,000 per object
Aggregate queriesYesNo
Search-term lengthn/a10,000 chars (logical operators dropped past 4,000)
Number of objects in one call1 (plus relationships)Many

The 50,000 SOQL cap rarely bites. The 2,000 SOSL cap bites all the time. If you run a SOSL without a LIMIT and one of your objects has thousands of matches, SOSL silently stops at 2,000 and the user has no idea they are seeing a slice.

Wildcards also work differently. SOSL supports * (zero or more chars, middle or end) and ? (one char, middle or end). SOQL LIKE uses % and _. Mixing those up is a one-character bug that reads like a missing-result bug.

// SOSL wildcard: zero or more characters at the end
List<List<SObject>> wide = [
    FIND 'John*'
    IN NAME FIELDS
    RETURNING Contact(Id, FirstName, LastName)
];
 
// SOQL LIKE wildcard: same idea, different syntax
List<Contact> narrow = [
    SELECT Id, LastName
    FROM Contact
    WHERE LastName LIKE 'John%'
    LIMIT 100
];

Dynamic SOSL When You Need It

Sometimes the search term is not known until runtime. Apex binds SOSL variables with the : colon, the same as SOQL, but only in static SOSL. For anything that builds the query from user input, build a string and call Search.query():

public static List<List<SObject>> findAcrossObjects(String term) {
    String safe = String.escapeSingleQuotes(term);
    String sosl =
        'FIND \'' + safe + '*\' IN ALL FIELDS ' +
        'RETURNING Account(Id, Name), Contact(Id, FirstName, LastName)';
    return Search.query(sosl);
}

Two details that matter here. First, the search term has to escape single quotes, otherwise user input like O'Brien breaks the SOSL string. String.escapeSingleQuotes is the right call. Second, the * wildcard is appended to the term, which is the common pattern for a "starts with" search bar. If you build SOSL by hand, these two details are the ones that turn into production incidents.

How To Pick, In Practice

A simple rule holds almost every time:

  • I know the object. SOQL.
  • I do not know the object. SOSL.
  • I need aggregates, joins, or strict filters. SOQL.
  • I need one call that spans many objects. SOSL.

If you are still not sure, write the question down in one sentence. If the sentence starts with "show me every ..." you want SOQL. If it starts with "find anything that ..." you want SOSL.

Where To Practice Next

If you want to write real SOQL against a live org, the SOQL challenges walk you through the queries that come up most in PD1 prep and on the job. If you want a quick tour of how Salesforce hands you back List<List<SObject>> from SOSL, the Apex Collections lesson covers lists, sets, and maps with runnable snippets.

WW

About Warren Walters

Salesforce MVP and transformative mentor with 8+ years in the Salesforce realm. Founder of Lightning Challenge, dedicated to nurturing the next generation of Salesforce talent through hands-on practice and real-world coding challenges.

Visit Profile →
Share:

Related Posts