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 introduces long-awaited 10 MB and 25 MB Apex heap ceilings alongside native live integration tests in scratch orgs. Here is an architectural evaluation of what changes, what breaks, and how to safely adopt API version 68.0.

The short answer

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

Key takeaways Audit asynchronous integration workloads to take advantage of the 25 MB heap limit, but retain strict payload pagination to avoid hitting the unchanged 50,000 SOQL query row ceiling. Split CI/CD execution into fast mocked deployment suites and serialized scratch org `@IntegrationTest` runs to handle unmocked HTTP testing without blocking deployment gates. Enforce ESLint rules on LWC templates to restrict GA complex expressions to basic formatting, preventing business logic from leaking out of JavaScript controllers. Isolate dynamic SOQL in AppExchange managed packages by declaring explicit namespaces to prevent subscriber custom fields from shadowing packaged queries. Pin all middleware REST endpoints to explicit API versions rather than adopting the unversioned latest endpoint in enterprise production integrations.

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

Adopting these features requires clear operational boundaries. Upgrading requires understanding how memory increases interact with unchanged governor ceilings, how unmocked test suites affect automated pipelines, and why unversioned API aliases pose risks to enterprise integrations as detailed in Salesforce Ben's release coverage.

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. This runtime ceiling change eliminates memory failures when parsing large JSON responses from external systems or constructing 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, but record limits and CPU time limits remain unchanged. The table below outlines how runtime boundaries compare 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 via the @IntegrationTest annotation. Unlike standard test executions that isolate transactions using HttpCalloutMock and execute rollbacks, @IntegrationTest 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 exclusively through asynchronous execution (runTestsAsynchronous), cannot execute in sandboxes or production orgs, and do not generate coverage toward the 75% deployment requirement. CI/CD automation must 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 using sf apex run test to verify live third-party contracts, ensuring only one test runs per org at a time.

Resolving Dynamic SOQL Namespace Collisions

For managed package authors (ISVs), subscriber orgs defining custom fields that share an API name with a packaged field can alter dynamic SOQL query behavior. Winter '27 resolves this ambiguity by adding an explicit namespace parameter via 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 forces the query engine to bind directly to the package schema, ignoring 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 directly within 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 operating under legacy Lightning Locker, external custom elements will fail to mount correctly.

API Governance and Recompilation

Winter '27 introduces an unversioned URI parameter (/services/data/latest/) for REST API calls as documented in the Salesforce release schedule notes. While using an unversioned endpoint simplifies development in test environments, avoid using /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/) that are 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, providing accurate context for internal developer tooling and schema linters.

To improve release maintenance, the platform now supports recompiling only invalid Apex classes and triggers. This reduces build and deployment validation times in large orgs by avoiding unnecessary full-codebase recompilations when updating individual classes.

What to Watch For

  • Live Test Data Residue: Exceptions thrown inside @IntegrationTest methods before reaching the @TearDown method leave dirty records in your scratch org. Design test cleanup steps defensively to handle partial test executions.
  • CI Concurrency Bottlenecks: Scratch orgs allow only one concurrent @IntegrationTest execution at a time. CI runners attempting to execute parallel suites against a single scratch org will fail with concurrency errors.
  • LWS Dependencies for External Components: Verify that Lightning Web Security is enabled in setup before deploying templates containing 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: Package codebases using dynamic SOQL must be reviewed to 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 do not contribute to the 75% code coverage calculation required for production deployments.

Can I use lwc:external with legacy Lightning Locker?

No. The `lwc:external` directive for rendering third-party web components requires Lightning Web Security (LWS) to be enabled in the target Salesforce org.

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

No. The synchronous SOQL query row limit remains strictly capped at 50,000 records regardless of the new 10 MB synchronous and 25 MB asynchronous heap limits.

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