Tuesday, 8 September 2026

Increased Apex Heap Size in Winter '27


Image generated by ChatGPT 5.6 based on a prompt by Bob Buzzard

Introduction

The Winter '27 release of Salesforce gave us an unexpected uplift in the Apex heap limit. Synchronous Apex gets 10Mb, an increase of 4Mb or 66% over the previous 6Mb, while asynchronous Apex gets a whopping 25Mb, an increase of 13Mb or 108% over the previous 12Mb. Given that all the memory in the world is currently being consumed by AI data centres, this is not something I was expected.

There's also a really nice touch in Apex Settings while we're in the release transition period - we can ask non-production Winter '27 orgs to apply the Summer '26 heap limit, so we don't inadvertently release code that relies on a 10Mb heap limit to orgs that max out at 6Mb. 

I've previously messed with heap limits when trying out Zip Handling in Apex back in February 2025. I was able to briefly push the 6Mb limit to 25Mb when processing a large zip file, so I was keen to see what could be achieved with 10Mb.

After spinning up a Winter '27 preview scratch org and deploying the Zip Handler sample code, I set about pushing the limit. A zip file of 28Mb presented no problem, but also didn't push the heap much further than my original tests in Spring '25. The non-linear nature of compression algorithms I guess. A zip file of 100Mb blew up pretty much immediately when retrieving the file body. Much as I expected, but it would have been cool if it had worked. Splitting the difference to 75Mb suffered the same fate.

Cutting the zip file down to 51Mb hit the sweet spot, as my LWC confirmed:

    51,810,068 byte zip file consumed 201 msec of cpu and 50,783,500 bytes of heap

The CPU is low because there are only a couple of files in there, and they are MOV files which are already compressed. The heap size is impressive though - Apex has (briefly) allowed me to consume 5 times the documented limit. Obviously relying on this in any production scenario would likely be a career-limiting choice - it's all fun and games until the runtime notices, kills my transaction, and leaves me with a file that I've accepted but can't actually process.

Bigger isn't Always Better

The increased heap limit is, of course, very welcome. That said, there's a couple of things I think it's important to bear in mind:

  • Heap isn't throughput. The gating factor on your automated process may have been heap, but just because you have more heap doesn't mean you can process as many records as you can stuff into a transaction. The other limits remain in place, and retrieving more records to process will likely push your CPU consumption higher. Code that scales poorly will simply have more room to consume resources before it fails, so it's important to understand how your code behaves as the inputs grow. (Growth Testing is something I cover in my new book, Software Testing on the Salesforce Platform).
  • Just because you can retrieve tons of data, doesn't mean you should deliver it. A larger heap means more information can be sent back to the user, but always consider the user experience. Thousands of records dumped in a table that a user has to scroll through can quickly get overwhelming, and they'll be treated to a longer wait while all that information makes its way through the layers. Sending a limited set of results back to the user with the ability to filter is often better received than sending everything because nothing was stopping you. Similarly, increased volumes of data returned from an API call might overwhelm a downstream system, 
A more nuanced consideration is that you might see issues as code silently becomes more capable. I'm sure there are business processes out that that always fail if more than 'x' records are selected for processing. Everyone has got used to this, and maybe in the odd case it's a key attribute of the automation. All of a sudden this code doesn't fail until it gets '2x' records to process, but the increased volumes it can handle cause issues elsewhere. Beware historical assumptions on when transactions would be terminated automatically.

Yesterday's Best Practice is Still the Right Approach

Writing Apex code to conserve limits and break large workloads into separate transactions is still the way to do it. Just because there is more heap to work with doesn't mean we can start retrieving all fields regardless of whether we need them, or leave copies of everything hanging around. The increased heap limit allows us to handle legitimately larger workloads, but we shouldn't view it as a target to be hit on every transaction, or stop caring about heap consumption.

More Information


 

 

Wednesday, 2 September 2026

Apex Integration Testing in Winter '27


Image created by ChatGPT 5.6 based on a prompt from Bob Buzzard

Introduction

Apex integration testing was launched in Developer Preview in the Summer '26 Salesforce release. In my blog post on this new functionality, I noted that it was:

limited to interactions with the Data 360 and Agentforce Salesforce services, but hopefully this will be relaxed in the future and we'll be able to make callouts to any authorised endpoint that we choose. 

In Winter '27 the future is here! While the feature is still in Developer Preview, your tests can now make HTTP callouts to any authorised endpoint, including external services configured via named credentials.

Sample


The sample code (available at this Github repo) needs to be executed against a Developer scratch org running the Winter '27 release (in preview at the time of writing) with the ApexIntegrationTests feature, which you can specify by adding these couple of lines to your project-scratch-def.json file:
   "release": "preview",
   "features": ["EnableSetPasswordInApi", "ApexIntegrationTests", "Einstein1AIPlatform"],

I've used my standard endpoint for proof of concept work - the free tier of Agify (agify.io), which estimates ages based on names. This (currently) doesn't require authentication, works off a simple GET request with the name as a parameter, and returns a small, easily understood JSON response. There's a very simple Agify service, consisting of a getAge() method that sends my name off for an estimate.

The integration test simply executes the service's getAge() method and verifies that the response contains the supplied name. There's not much else worth asserting here - I can't be sure what age will be returned, as the response can change in line with the underlying Agify dataset:

@IntegrationTest
public with sharing class AgifyServiceIntegrationTest {
    @IntegrationTest
    public static void testServiceInteraction() {
        AgifyService.AgifyResponse resp=AgifyService.getAge('Keir Bowden');
        Assert.areEqual('Keir Bowden', resp.name, 
            'The name returned from the service should match the input name.');
    }
}

The key aspect is that the test completes successfully. Running this against the Summer '26 release gives the following error:

12:41:27:012 FATAL_ERROR System.TypeException: Methods defined as TestMethod do not support Web service callouts

(Clearly it wasn't worth defining a bespoke error message for the single release that integration testing didn't allow callouts, but I must defend myself here - I have no "Methods defined as TestMethod", just methods decorated with @IntegrationTest).

I'm really pleased that it's only taken one release to open up integration testing past Agentforce and Data 360. My next hope is that integration testing is never allowed in a production environment - it's just too dangerous in my opinion, especially now there can be callouts to all manner of other production systems. Scratch orgs and sandboxes will be fine for the vast majority of us, and those that really do need to run it all in production can do so outside of a testing framework.

More Information


Follow on LinkedIn