Difference between Static SOQL and Dynamic SOQL in Salesforce Apex
Salesforce Object Query Language, usually written as SOQL, is used in Apex to read records from Salesforce objects. The main difference between static SOQL and dynamic SOQL is when the query is defined. A static SOQL query is written directly in Apex between square brackets, while a dynamic SOQL query is built as a string at run time and executed with Database.query().
In most Apex classes, static SOQL should be the first choice because it is easier to read and Salesforce can validate the object names, field names, and query syntax earlier. Dynamic SOQL is useful when the selected fields, object name, filter conditions, or sort order must change based on user input, configuration, or reusable framework logic.
Static SOQL vs Dynamic SOQL quick comparison
| Point of difference | Static SOQL | Dynamic SOQL |
|---|---|---|
| How the query is written | Written directly inside square brackets in Apex. | Built as a string and passed to Database.query(). |
| Best use case | Known object, known fields, and known filter structure. | Object, fields, filters, or ordering must be decided at run time. |
| Readability | Usually easier to read and maintain. | Can become hard to maintain if string building is not organized. |
| Validation | Salesforce can validate the query structure more directly. | Some errors are found only when the dynamic query executes. |
| Security concern | Safer by default when bind variables are used correctly. | Needs careful input handling to avoid SOQL injection. |
Static SOQL statements in Apex
A static SOQL query is written directly in Apex using square brackets. It is suitable when the object name, field names, and main filter logic are already known while writing the code. Static SOQL is commonly used in triggers, controllers, batch Apex, queueable classes, and service classes where the query structure does not need to change.
Static SOQL can still use Apex variables through bind variables. That means the query can accept changing values such as an Account Id or Last Name without making the query itself dynamic.
Contact[] contacts = [SELECT testfield__C, FirstName, LastName FROM Contact WHERE LastName = 'Prasanth'];
In practical Apex code, it is usually better to query the Id field also and use a bind variable instead of hard-coding the filter value.
String contactLastName = 'Prasanth';
List<Contact> contacts = [
SELECT Id, FirstName, LastName, Email
FROM Contact
WHERE LastName = :contactLastName
];
When to use static SOQL in Salesforce Apex
- Use static SOQL when the Salesforce object is known, such as
Account,Contact, or a specific custom object. - Use it when the selected fields are fixed in the Apex logic.
- Use it when only filter values change, because bind variables can handle changing values.
- Use it when readability and maintainability are more important than query flexibility.
Dynamic SOQL in Apex
Dynamic SOQL refers to the creation of a SOQL query string at run time with Apex code. Dynamic SOQL enables you to create more flexible applications. For example, you can create a search based on input from an end user, choose fields from configuration, or query different objects from reusable code. This is the major difference between static SOQL and dynamic SOQL.
- Dynamic SOQL helps when the query structure is not completely known until the code runs.
- To create a dynamic SOQL query at run time, use the
Database.query()method. - Dynamic SOQL should be written carefully because string concatenation can create syntax errors or security issues if user input is not handled properly.
To create Dynamic SOQL query at run time, use the database query method as shown below.
List<sObject> sObject = Database.query(string);
The following example builds the field list and filter dynamically, then executes the query with Database.query().
String objectName = 'Contact';
String fieldList = 'Id, FirstName, LastName, Email';
String lastNameValue = 'Prasanth';
String queryString = 'SELECT ' + fieldList +
' FROM ' + objectName +
' WHERE LastName = :lastNameValue';
List<sObject> records = Database.query(queryString);
When to use dynamic SOQL in Salesforce Apex
- Use dynamic SOQL when the object name is selected at run time.
- Use it when the list of fields comes from custom metadata, field sets, or admin configuration.
- Use it when filters are optional and the final
WHEREclause must be assembled based on available values. - Use it for generic search screens where users can choose fields, filters, or sort order.
- Use it in reusable framework code that must work across multiple Salesforce objects.
Static SOQL bind variables are often enough
A common mistake is using dynamic SOQL only because the filter value changes. A changing value does not require dynamic SOQL. Static SOQL supports bind variables, and that is usually cleaner.
Id accountIdValue = '001000000000000AAA';
List<Contact> contacts = [
SELECT Id, FirstName, LastName
FROM Contact
WHERE AccountId = :accountIdValue
];
In this example, only the value of accountIdValue changes. The object name, selected fields, and filter structure are fixed, so static SOQL is the better option.
Dynamic SOQL syntax with Database.query()
The general syntax for dynamic SOQL is to store the query in a string and pass that string to Database.query(). The return type is usually List<sObject> when the object type is not known at compile time.
String queryString = 'SELECT fieldNames FROM ObjectName WHERE condition';
List<sObject> records = Database.query(queryString);
If the object is known, you can cast the result to a specific sObject list only when the query actually returns that object type.
String queryString = 'SELECT Id, Name FROM Account LIMIT 10';
List<Account> accounts = Database.query(queryString);
SOQL injection risk in dynamic SOQL
Dynamic SOQL must be written carefully when any part of the query depends on user input. If user input is directly joined into the query string, the final SOQL statement may not behave as intended. Prefer bind variables for values and validate any dynamic object names, field names, and sort directions before adding them to the query.
For string values that must be concatenated, use String.escapeSingleQuotes(). However, escaping is not a replacement for checking whether a field or object is actually allowed in your Apex logic.
String userSearchText = 'Prasanth';
String safeSearchText = String.escapeSingleQuotes(userSearchText);
String queryString = 'SELECT Id, FirstName, LastName ' +
'FROM Contact ' +
'WHERE LastName = \'' + safeSearchText + '\'';
List<Contact> contacts = Database.query(queryString);
When possible, use bind variables in dynamic SOQL for filter values. This keeps values separate from the query structure.
String lastNameValue = 'Prasanth';
String queryString = 'SELECT Id, FirstName, LastName FROM Contact WHERE LastName = :lastNameValue';
List<Contact> contacts = Database.query(queryString);
Choosing between static SOQL and dynamic SOQL
Use this simple decision rule: if only the values change, use static SOQL with bind variables. If the query structure changes, use dynamic SOQL. Query structure means the object, fields, conditions, grouping, ordering, or limit clauses are assembled at run time.
| Requirement | Recommended SOQL type | Reason |
|---|---|---|
| Find Contacts for a known Account Id | Static SOQL | The object and fields are fixed; only the value changes. |
| Let users choose search filters on a custom search page | Dynamic SOQL | The WHERE clause may change at run time. |
| Query fields selected from a field set | Dynamic SOQL | The field list is not fixed in the Apex code. |
| Read Accounts with a fixed status filter | Static SOQL | The query is predictable and easier to validate. |
| Build a generic export tool for multiple objects | Dynamic SOQL | The object and fields may vary by request. |
Governor limit reminder for both static and dynamic SOQL
Static SOQL and dynamic SOQL both run under the same Apex governor limits. Dynamic SOQL does not avoid SOQL query limits, row limits, or CPU time limits. Avoid placing either type of SOQL query inside a loop. Collect record Ids first, then run one query outside the loop whenever possible.
Set<Id> accountIds = new Set<Id>();
for (Contact con : Trigger.new) {
if (con.AccountId != null) {
accountIds.add(con.AccountId);
}
}
List<Account> accounts = [
SELECT Id, Name
FROM Account
WHERE Id IN :accountIds
];
Common mistakes with static and dynamic SOQL
- Using dynamic SOQL for simple variable values: Use static SOQL with bind variables when only the value changes.
- Hard-coding user input into a dynamic query: Validate or escape user-provided values before using them in a query string.
- Forgetting spaces while concatenating query strings: Missing spaces can produce invalid SOQL such as
ContactWHERE. - Querying fields the running user cannot access: Review object-level and field-level security requirements for your use case.
- Putting SOQL inside loops: Both static and dynamic SOQL count against governor limits.
Official Salesforce references for SOQL in Apex
For complete syntax details, refer to the Salesforce documentation for Dynamic SOQL, SOQL queries in Apex, and Apex governor limits.
FAQ on static SOQL and dynamic SOQL
What is the difference between static SOQL and dynamic SOQL?
Static SOQL is written directly inside square brackets in Apex. Dynamic SOQL is built as a string at run time and executed with Database.query(). Static SOQL is better when the query structure is fixed, while dynamic SOQL is used when the object, fields, filters, or sorting need to change at run time.
Should I use dynamic SOQL when only the filter value changes?
No. If only the filter value changes, use static SOQL with a bind variable. Dynamic SOQL is normally needed only when the query structure itself changes.
Which is safer: static SOQL or dynamic SOQL?
Static SOQL is generally safer and easier to maintain because the query is written directly in Apex. Dynamic SOQL can also be safe, but user input must be validated or escaped, and bind variables should be used for values whenever possible.
Does dynamic SOQL avoid Salesforce governor limits?
No. Static SOQL and dynamic SOQL both follow the same Apex governor limits. Dynamic SOQL does not allow unlimited queries or unlimited rows.
Can dynamic SOQL return a strongly typed list?
Yes, if the query returns a known object type. For example, a dynamic query on Account can be assigned to List<Account>. If the object type is not known, use List<sObject>.
Editorial QA checklist for this static SOQL vs dynamic SOQL tutorial
- Confirm that static SOQL examples use square brackets and valid Apex-style bind variables.
- Confirm that dynamic SOQL examples use
Database.query()and do not imply that dynamic SOQL bypasses governor limits. - Check that the tutorial clearly recommends static SOQL when only filter values change.
- Check that dynamic SOQL security guidance mentions bind variables, input validation, and
String.escapeSingleQuotes(). - Verify that official Salesforce documentation links are included for dynamic SOQL, SOQL in Apex, and governor limits.
TutorialKart.com