Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
3D render of a glowing core representing Salesforce Winter 27 developer features and architecture updates
Apex

Salesforce Winter '27 Developer Architecture Guide

Winter '27 raises the Apex heap ceilings to 10 MB and 25 MB and adds native live integration tests in scratch orgs. This is an architectural read on what changes, what breaks, and how to adopt API version 68.0 safely.

The short answer

Salesforce Winter '27 (API version 68.0) raises the synchronous and asynchronous Apex heap limits to 10 MB and 25 MB, and adds native `@IntegrationTest` classes for unmocked HTTP callouts in scratch orgs. Adopting it means restructuring CI/CD pipelines to isolate unmocked tests, and refactoring dynamic SOQL in managed packages with explicit namespace options.

Key takeaways Audit asynchronous integration workloads against the new 25 MB heap limit, and keep strict payload pagination so you do not hit the unchanged 50,000 SOQL query row ceiling. Split CI/CD execution into fast mocked deployment suites and serialized scratch org @IntegrationTest runs, so unmocked HTTP testing does not block deployment gates. Enforce ESLint rules that hold GA complex expressions in LWC templates to basic formatting, so business logic stays inside the JavaScript controllers. Declare explicit namespaces for dynamic SOQL in AppExchange managed packages so subscriber custom fields cannot shadow packaged queries. Pin middleware REST endpoints to explicit API versions instead of the unversioned latest endpoint in enterprise production integrations.

Salesforce Winter '27 (API version 68.0) changes core runtime constraints that have shaped enterprise architecture for over a decade. The release raises heap memory thresholds, adds native live integration testing, and introduces explicit namespace resolution for dynamic queries.

Adopting these features takes clear operational boundaries: how the memory increases interact with governor ceilings that did not move, how unmocked test suites affect automated pipelines, and why unversioned API aliases are a risk for enterprise integrations, as covered in Salesforce Ben's release write-up.

Managing memory ceilings and query guardrails

Winter '27 increases the synchronous Apex heap limit from 6 MB to 10 MB and the asynchronous heap limit from 12 MB to 25 MB. The higher ceiling removes memory failures when parsing large JSON responses from external systems or building complex in-memory document structures.

public with sharing class DocumentPayloadProcessor {
    public static void parseAndStage(Id outboundPayloadId) {
        ContentVersion fileData = [SELECT VersionData FROM ContentVersion WHERE Id = :outboundPayloadId LIMIT 1];
        
        // Inspect available execution capacity at runtime
        Integer currentLimit = Limits.getLimitHeapSize();
        System.debug(LoggingLevel.INFO, 'Active Heap Ceiling (bytes): ' + currentLimit);
        
        // Large JSON payload transformations now have headroom up to 10 MB synchronously
        Map<String, Object> parsedStructure = (Map<String, Object>) JSON.deserializeUntyped(fileData.VersionData.toString());
        processPayloadNodes(parsedStructure);
    }
    
    private static void processPayloadNodes(Map<String, Object> nodes) {
        // Transform and persist records
    }
}

I have seen this memory increase tempt teams into pulling entire object histories into memory instead of writing selective queries, which crashes transactions against the 50,000 query row limit. The heap expanded; record limits and CPU time limits did not. The table below compares runtime boundaries across execution contexts.

Runtime Metric Legacy Sync Limit Winter '27 Sync (v68.0) Legacy Async Limit Winter '27 Async (v68.0)
Max Heap Allocation 6 MB 10 MB 12 MB 25 MB
Max SOQL Query Rows 50,000 50,000 50,000 50,000
Max CPU Execution Time 10,000 ms 10,000 ms 60,000 ms 60,000 ms
SOQL Query Timeout 120 seconds 120 seconds 120 seconds 120 seconds

Isolating scratch-only live integration tests

Winter '27 adds native integration testing under Developer Preview through the @IntegrationTest annotation. Standard test executions isolate transactions with HttpCalloutMock and then roll back. An @IntegrationTest class makes live network calls to external endpoints and commits database changes across steps.

To enable this in your project configuration, add the feature flag to project-scratch-def.json:

{
  "orgName": "Integration-Testing-Scratch",
  "edition": "Developer",
  "features": ["ApexIntegrationTests"],
  "settings": {
    "lightningExperienceSettings": {
      "enableS1DesktopEnabled": true
    }
  }
}

Because automated database rollbacks are disabled during live integration tests, you must explicitly manage data setup and teardown phases using @BeforeClass and @TearDown.

@IntegrationTest
public with sharing class PaymentGatewayIntegrationTest {
    private static String stagingExternalRefId;

    @BeforeClass
    public static void setupSharedState() {
        Payment_Audit__c audit = new Payment_Audit__c(
            Status__c = 'Pending',
            Idempotency_Key__c = 'TEST-KEY-' + Datetime.now().getTime()
        );
        insert audit;
        stagingExternalRefId = audit.Idempotency_Key__c;
        IntegrationTest.commitTestOnly();
    }

    @IntegrationTest
    public static void verifyLiveChargeSettlement() {
        PaymentClient client = new PaymentClient();
        // Makes a live outbound HTTP callout to the target endpoint
        HttpResponse res = client.executePayment(stagingExternalRefId, 500.00);
        
        System.assertEquals(200, res.getStatusCode(), 'Expected live gateway acknowledgment');
    }

    @TearDown
    public static void cleanPersistentState() {
        List<Payment_Audit__c> staleRecords = [
            SELECT Id FROM Payment_Audit__c WHERE Idempotency_Key__c = :stagingExternalRefId
        ];
        if (!staleRecords.isEmpty()) {
            delete staleRecords;
            IntegrationTest.commitTestOnly();
        }
    }
}

These tests run only through asynchronous execution (runTestsAsynchronous), cannot execute in sandboxes or production orgs, and generate no coverage toward the 75% deployment requirement. CI/CD automation has to split pipeline runs into distinct stages:

  1. Run standard @IsTest suites on pull requests using mocked boundaries for fast feedback and package coverage verification.
  2. Spin up dedicated scratch orgs with ApexIntegrationTests enabled in a nightly or staging pipeline.
  3. Execute @IntegrationTest suites sequentially with sf apex run test to verify live third-party contracts, so that only one test runs per org at a time.

Resolving dynamic SOQL namespace collisions

For managed package authors (ISVs), a subscriber org that defines a custom field sharing an API name with a packaged field can alter dynamic SOQL query behavior. Winter '27 resolves the ambiguity with an explicit namespace parameter, available through Database.QueryOptions and the SET OPTIONS clause.

public with sharing class PackageDataSelector {
    public static List<SObject> queryRecordsWithNamespaceIsolation(Id parentRecordId, String packageNamespace) {
        // Prevent subscriber-defined fields from shadowing packaged fields
        String queryString = 
            'SELECT Id, Billing_Status__c ' +
            'FROM Invoice__c ' +
            'WHERE Account__c = :parentRecordId ' +
            'SET OPTIONS explicitNamespace = :packageNamespace';
            
        return Database.query(queryString);
    }
}

When dynamic queries evaluate field tokens at runtime, passing explicitNamespace binds the query engine directly to the package schema and ignores subscriber custom fields that share the same suffix.

Modernising the front-end tier with LWC

Lightning Web Components in API version 68.0 promote complex template expressions and the lwc:external directive to General Availability (GA). Complex template expressions allow inline data formatting and conditions inside template markup, without boilerplate getters in the JavaScript class.

<!-- accountBalanceCard.html -->
<template>
    <lightning-card title="Billing Summary">
        <div class="slds-p-around_medium">
            <p>Outstanding: {account.totalBalance - account.creditedAmount}</p>
            <p class={account.isDelinquent && account.riskScore > 75 ? 'slds-text-color_error' : 'slds-text-color_default'}>
                Status: {account.isDelinquent ? 'Action Required' : 'Current'}
            </p>
        </div>
    </lightning-card>
</template>

The lwc:external directive enables standard custom elements inside LWC templates without wrapping them in an iframe or loading them through static resources.

<!-- chartingContainer.html -->
<template>
    <div class="chart-wrapper">
        <third-party-gauge-chart 
            lwc:external 
            max-value="100" 
            current-value={metricScore}>
        </third-party-gauge-chart>
    </div>
</template>

This directive requires Lightning Web Security (LWS) to be active. In orgs still running legacy Lightning Locker, external custom elements fail to mount correctly.

API governance and recompilation

Winter '27 introduces an unversioned URI parameter (/services/data/latest/) for REST API calls, documented in the Salesforce release schedule notes. An unversioned endpoint simplifies development in test environments, but avoid /latest/ in production middleware such as MuleSoft, Boomi, or event-driven integrations.

Unpinned endpoints expose integrations to silent schema breaking changes, stricter type enforcement, or altered standard endpoint behaviors during tri-annual major release upgrades. Production integration patterns should always use explicit, pinned versions such as /services/data/v68.0/, updated through structured regression testing.

For developer tooling and IDE support, the Apex Symbol API enters Beta as a Tooling API REST resource. It exposes compiler-resolved metadata for types, methods, and signatures, which gives internal developer tooling and schema linters accurate context.

The platform also supports recompiling only invalid Apex classes and triggers. That cuts build and deployment validation times in large orgs, because updating individual classes no longer forces a full-codebase recompilation.

What to watch for

  • Live test data residue. Exceptions thrown inside @IntegrationTest methods before the @TearDown method runs leave dirty records in your scratch org. Design cleanup steps defensively so they handle partial test executions.
  • CI concurrency bottlenecks. Scratch orgs allow only one concurrent @IntegrationTest execution at a time. CI runners that try to execute parallel suites against a single scratch org fail with concurrency errors.
  • LWS dependencies for external components. Verify that Lightning Web Security is enabled in setup before deploying templates that contain the lwc:external directive.
  • Inline logic sprawl. Complex expressions in LWC templates should handle display formatting only. Keep business rules, validations, and state mutations inside the JavaScript class.
  • Dynamic SOQL upgrades. Review package codebases that use dynamic SOQL and add explicitNamespace wherever subscriber-defined schema could shadow packaged fields.

Originally reported by salesforceben.com

Frequently asked questions

Do Apex Integration Tests satisfy the 75% deployment code coverage requirement?

No. Classes annotated with `@IntegrationTest` run asynchronously in scratch orgs only, and they do not count toward the 75% code coverage required for production deployments.

Can I use lwc:external with legacy Lightning Locker?

No. The `lwc:external` directive for rendering third-party web components works only where Lightning Web Security (LWS) is enabled in the target Salesforce org.

Does the increased heap limit raise the SOQL record retrieval count?

No. The synchronous SOQL query row limit stays capped at 50,000 records, whatever the new 10 MB synchronous and 25 MB asynchronous heap limits allow.

Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment