Reducing SOQL Overhead with Apex Platform Cache
Learn how to implement the Apex Platform Cache to reduce SOQL query counts and improve performance using the Cache‑Aside pattern for Org and Session data.
22 Jan 2026, 09:40 UTC

The Cost of Redundant Queries
In complex Salesforce environments, it is common for multiple triggers, helper classes, and controllers to request the same set of configuration data—such as custom metadata, mapping tables, or organizational settings—within a single transaction. While a single SOQL query is cheap, repeating that query across different layers of the execution stack consumes the 100-query synchronous governor limit and increases latency.
The Platform Cache allows you to store these frequently accessed, slowly changing values in memory. By bypassing the database layer, you can reduce the total number of SOQL calls and speed up the response time for the end user.
Org Cache vs. Session Cache
Platform Cache is split into two distinct partitions based on the scope of the data:
- Org Cache: Stores data that is identical for every user in the organization. This is ideal for global settings, tax rates, or custom mapping logic.
- Session Cache: Stores data specific to a single user's session. This is useful for user preferences or temporary state data that should persist across multiple requests but not be shared with others.
Implementing a Cache‑Aside Pattern
The most effective way to use the cache is the "Cache‑Aside" (or Lazy Loading) pattern. Instead of blindly trusting the cache, the code checks for the value, fetches it from the database if it is missing, and then populates the cache for the next request.
Worked Example: Caching Custom Metadata
Assume you have a Custom Metadata Type called App_Config__mdt that stores a system‑wide timeout value. Rather than querying this in every method, you can wrap the access in a service class.
// Run this in an Apex Class.
// Requires a Cache Partition named 'AppConfigPartition' created in Setup.
public class ConfigService {
private static final String CACHE_PARTITION = 'AppConfigPartition';
private static final String CACHE_KEY = 'SystemTimeout';
public static Integer getTimeoutValue() {
// 1. Attempt to retrieve from Org Cache
Integer timeout = Cache.Org.get(CACHE_PARTITION, CACHE_KEY);
if (timeout == null) {
// 2. Cache Miss: Query the database
App_Config__mdt config = [SELECT Value__c FROM App_Config__mdt WHERE DeveloperName = 'Timeout' LIMIT 1];
timeout = Integer.valueOf(config.Value__c);
// 3. Store in cache for future requests
Cache.Org.put(CACHE_PARTITION, CACHE_KEY, timeout);
}
return timeout;
}
}
Execution and Verification
To verify this implementation, run the following in the Developer Console's Anonymous Apex window:
// First call: Triggers a SOQL query
System.debug('Value 1: ' + ConfigService.getTimeoutValue());
// Second call: Retrieves from memory (0 SOQL queries)
System.debug('Value 2: ' + ConfigService.getTimeoutValue());
// Check the Debug Log: The 'Number of SOQL queries' should only increment once.
Trade‑offs and Critical Limitations
Platform Cache is not a replacement for a database; it is a performance optimization. You must account for the following constraints:
Stale Data
The cache does not automatically update when the underlying record changes. If an administrator updates the App_Config__mdt record, the cache will continue to serve the old value until it expires or is manually evicted using Cache.Org.remove(). For data that changes frequently, keep the TTL (Time To Live) short.
Serialization and Space
Only serializable objects can be stored. Furthermore, cache space is finite. If your partition fills up, Salesforce uses an eviction policy to remove older entries to make room for new ones. Your code must always handle null returns from Cache.get() to ensure the application doesn't crash when an item is evicted.
Availability
Platform Cache is an add‑on or limited by edition. If the feature is not enabled or the partition is deleted, Cache.get() will return null. The Cache‑Aside pattern described above handles this gracefully by falling back to a SOQL query.
Practical Checklist for Deployment
- Setup: Ensure a Cache Partition is created in Setup > Platform Cache with the correct name and allocated space.
- Permissions: Verify that the executing user's profile has access to the partition.
- Monitoring: Use the
Limits.getQueries()method in your debug logs to confirm the reduction in database load.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.