{"id":16680,"date":"2026-06-15T09:38:52","date_gmt":"2026-06-15T09:38:52","guid":{"rendered":"https:\/\/dianapps.com\/blog\/?p=16680"},"modified":"2026-06-16T05:42:32","modified_gmt":"2026-06-16T05:42:32","slug":"salesforce-spring-26-release-developers-guide","status":"publish","type":"post","link":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/","title":{"rendered":"The Salesforce Developer&#8217;s Guide to the Spring &#8217;26 Release"},"content":{"rendered":"<h3><span class=\"ez-toc-section\" id=\"Quick-Overview\"><\/span><span style=\"font-weight: 400;\">Quick Overview:<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">This guide covers all major Salesforce Spring &#8217;26 developer updates, from LWC template expressions and Apex Cursors to Agentforce Builder, mandatory security migrations, Flow logging, GraphQL mutations, and more.<\/span><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Complex Template Expressions in LWC (Beta), write JS inline in templates<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Apex Cursors are now Generally Available, process up to 50M records<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Agentforce Builder with Canvas + Script views for AI agent development<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">RunRelevantTests for faster, dependency-aware deployments (API v66)<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Agent Script, YAML-like DSL for deterministic agent behavior<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">TypeScript support for LWC via @salesforce\/lightning-types<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">External Client Apps replacing Connected Apps (mandatory migration)<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Flow Logging, Kanban boards, and inline-editable data tables<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Triple DES retirement deadline, Summer &#8217;26 (urgent action required)<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">GraphQL mutations are now supported in API v66<\/span><\/li>\n<\/ul>\n<h1><span class=\"ez-toc-section\" id=\"Why-Spring-26-Is-a-Milestone-Release-for-Developers\"><\/span><span style=\"font-weight: 400;\">Why Spring &#8217;26 Is a Milestone Release for Developers<\/span><span class=\"ez-toc-section-end\"><\/span><\/h1>\n<p><span style=\"font-weight: 400;\">Every Salesforce release matters.\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">But the Salesforce Spring &#8217;26 update feels different. This isn&#8217;t just a collection of quality-of-life improvements; it&#8217;s a definitive shift in how the platform thinks about the developer experience, AI integration, and long-term architectural strategy.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">As one Salesforce Developer Advocate noted, Spring &#8217;26 is &#8220;a gobstopper of a release for developers&#8221;, packed with GA features that remove years-old friction points, Beta features that preview the agentic future, and mandatory security changes that demand immediate attention.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">The defining theme of this release is the move toward what Salesforce calls the &#8220;Agentic Enterprise&#8221;, a model where AI agents and human developers co-build, co-test, and co-deploy across every layer of the platform.\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">If you&#8217;ve been watching Agentforce evolve since its introduction, Spring &#8217;26 is where it starts to feel like native infrastructure rather than a bolted-on product.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">In this guide, we&#8217;ll break down every developer-relevant feature across LWC, Apex, Agentforce 360 platform, Flow, APIs, and security, so you can prioritize what to test first, what to plan for, and what to act on immediately.\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">Whether you&#8217;re a solo Salesforce developer, part of an enterprise team, or partnering with a specialist provider of <\/span><a href=\"https:\/\/dianapps.com\/salesforce-development-services\"><b>Salesforce development services<\/b><\/a><span style=\"font-weight: 400;\">, this guide has you covered.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><i><span style=\"font-weight: 400;\">Pro Tip:<\/span><\/i><span style=\"font-weight: 400;\"> Sandbox preview for Spring &#8217;26 began January 9, 2026. If you haven&#8217;t yet spun up a pre-release org, do it now; some Beta features require explicit activation in Setup before they appear.<\/span><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Release-Dates-Rollout-Timeline\"><\/span><span style=\"font-weight: 400;\">Release Dates &amp; Rollout Timeline<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">The Spring &#8217;26 release follows Salesforce&#8217;s standard phased rollout. Here&#8217;s the definitive timeline every developer should have bookmarked:<\/span><\/p>\n\n<table id=\"tablepress-197\" class=\"tablepress tablepress-id-197\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\">Date<\/th><th class=\"column-2\">Milestone<\/th><th class=\"column-3\">Details<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\">Dec 18, 2025<\/td><td class=\"column-2\">Pre-Release Dev Edition<\/td><td class=\"column-3\">Sign up for the standalone Developer Edition with all Spring '26 features.<\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\">Jan 9\u201310, 2026<\/td><td class=\"column-2\">Sandbox Preview Begins<\/td><td class=\"column-3\">Early access in sandboxes for safe exploration and validation.<\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\">Jan 16, 2026<\/td><td class=\"column-2\">Production Wave 1<\/td><td class=\"column-3\">Initial production instances upgraded. Check Salesforce Trust for your org.<\/td>\n<\/tr>\n<tr class=\"row-5\">\n\t<td class=\"column-1\">Feb 13, 2026<\/td><td class=\"column-2\">Production Wave 2<\/td><td class=\"column-3\">The majority of production orgs upgraded in this wave.<\/td>\n<\/tr>\n<tr class=\"row-6\">\n\t<td class=\"column-1\">Feb 20, 2026<\/td><td class=\"column-2\">Production Wave 3 (Final)<\/td><td class=\"column-3\">All remaining production environments upgraded. Spring '26 will be fully live globally.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-197 from cache -->\n<p>&nbsp;<\/p>\n<p><b><i>Important:<\/i><\/b><span style=\"font-weight: 400;\"> Several Spring &#8217;26 changes are enforced, not opt-in. Review the security migration section carefully. The Connected Apps retirement and Triple DES deprecation have hard deadlines with real consequences.\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><b><i>Mandatory Changes: Action Required Now<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400;\">Session IDs in outbound messages removed Feb 16, 2026. New Connected Apps are disabled by default. Triple DES SAML retires Summer &#8217;26. Full details in Section 9.<\/span><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Lightning-Web-Components-LWC-Updates-in-Spring26\"><\/span><span style=\"font-weight: 400;\">Lightning Web Components (LWC) Updates in Spring\u201926<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Spring &#8217;26 delivers a strong batch of LWC improvements, a new dynamic event listener directive, complete GraphQL CRUD support, a completed TypeScript rollout, a cleaner way to launch flows, and a long-overdue developer debugging tool<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"1-Dynamic-Event-Listeners\"><\/span><span style=\"font-weight: 400;\">1. Dynamic Event Listeners.<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Before Spring &#8217;26, every event handler had to be declared statically in your HTML template. If you wanted to swap behavior at runtime, you needed messy conditional rendering or manual addEventListener calls.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">The new LWC: on directive solves this cleanly. You pass a plain JavaScript object where each key is an event name, and each value is the handler function. LWC automatically rewires the listeners whenever the object reference changes, no template edits required.<\/span><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>How it works: <\/b><span style=\"font-weight: 400;\">Object keys are event names (click, mouseenter\u2026). Values are the functions that run when that event fires.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>The benefit: <\/b><span style=\"font-weight: 400;\">Swap an entire set of event behaviors at runtime from JavaScript alone, without ever touching the HTML template.<\/span><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\">&lt;template&gt;\r\n\u00a0 &lt;div class=\"slds-card slds-p-around_medium\"&gt;\r\n\u00a0\r\n\u00a0 \u00a0 &lt;!--\r\n\u00a0 \u00a0 \u00a0 lwc:on accepts a plain JS object.\r\n\u00a0 \u00a0 \u00a0 Keys = event names, values = handler functions.\r\n\u00a0 \u00a0 \u00a0 LWC rewires listeners when the object reference changes.\r\n\u00a0 \u00a0 --&gt;\r\n\u00a0 \u00a0 &lt;div class=\"interactive-box\" lwc:on={boxEventHandlers}&gt;\r\n\u00a0 \u00a0 \u00a0 &lt;span&gt;{message}&lt;\/span&gt;\r\n\u00a0 \u00a0 \u00a0 &lt;span&gt;{hint}&lt;\/span&gt;\r\n\u00a0 \u00a0 &lt;\/div&gt;\r\n\u00a0\r\n\u00a0 \u00a0 &lt;lightning-radio-group\r\n\u00a0 \u00a0 \u00a0 name=\"mode\"\r\n\u00a0 \u00a0 \u00a0 label=\"Interaction Mode\"\r\n\u00a0 \u00a0 \u00a0 options={modeOptions}\r\n\u00a0 \u00a0 \u00a0 value={currentMode}\r\n\u00a0 \u00a0 \u00a0 type=\"button\"\r\n\u00a0 \u00a0 \u00a0 onchange={handleModeChange}&gt;\r\n\u00a0 \u00a0 &lt;\/lightning-radio-group&gt;\r\n\u00a0\r\n\u00a0 &lt;\/div&gt;\r\n&lt;\/template&gt;<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">\u2014<\/span><\/p>\n<p>&nbsp;<\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\">import { LightningElement, track } from 'lwc';\r\n\u00a0\r\nexport default class DynamicEventListener extends LightningElement {\r\n\u00a0 \u00a0 @track currentMode = 'click';\r\n\u00a0 \u00a0 @track message\u00a0 \u00a0 = 'Interact with the box!';\r\n\u00a0\r\n\u00a0 \u00a0 modeOptions = [\r\n\u00a0 \u00a0 \u00a0 \u00a0 { label: 'Click Mode', value: 'click' },\r\n\u00a0 \u00a0 \u00a0 \u00a0 { label: 'Hover Mode', value: 'hover' },\r\n\u00a0 \u00a0 ];\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ Returning a different object causes LWC to swap event listeners.\r\n\u00a0 \u00a0 get boxEventHandlers() {\r\n\u00a0 \u00a0 \u00a0 \u00a0 switch (this.currentMode) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 case 'click':\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return { click: this.handleClick };\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 case 'hover':\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 mouseenter: this.handleMouseEnter,\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 mouseleave: this.handleMouseLeave,\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 };\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 default:\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return {};\r\n\u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 }\r\n\u00a0\r\n\u00a0 \u00a0 get hint() {\r\n\u00a0 \u00a0 \u00a0 \u00a0 return this.currentMode === 'click' ? '\ud83d\udc46 Click here' : '\ud83d\udd90\ufe0f Hover here';\r\n\u00a0 \u00a0 }\r\n\u00a0\r\n\u00a0 \u00a0 handleClick\u00a0 \u00a0 \u00a0 = () =&gt; { this.message = '\ud83d\uddb1\ufe0f You clicked!'; };\r\n\u00a0 \u00a0 handleMouseEnter = () =&gt; { this.message = '\u2728 Mouse entered!'; };\r\n\u00a0 \u00a0 handleMouseLeave = () =&gt; { this.message = '\ud83d\udc4b Mouse left!'; };\r\n\u00a0\r\n\u00a0 \u00a0 handleModeChange(event) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.currentMode = event.detail.value;\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.message = 'Switched to ' + this.currentMode + ' mode';\r\n\u00a0 \u00a0 }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><b><i>Key insight<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400;\">The getter returns a completely new object whenever the current mode changes. LWC&#8217;s reactivity system detects the new reference and seamlessly updates which events the element listens to, no removeEventListener calls, no if-blocks in the template. Source: LWC Recipes PR #1081.\u00a0<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"2-GraphQL-Mutations-in-LWC\"><\/span><span style=\"font-weight: 400;\">2. GraphQL Mutations in LWC<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Spring &#8217;26 completes GraphQL CRUD in LWC. The existing @wire(graphql) adapter handles reactive reads. The new executeMutation method provides an imperative API for creating, updating, and deleting data; use it anywhere you need to write data from JavaScript.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">Define your mutation once using the gql template literal, then call executeMutation with the query and variables. The response returns exactly the fields you requested.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><strong>\u00a0 graphqlMutationCreate.js<\/strong><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\" title=\"\u00a0 graphqlMutationCreate.js\">import { LightningElement } from 'lwc';\r\nimport { gql, executeMutation } from 'lightning\/graphql';\r\n\u00a0\r\n\/\/ Define the mutation once at the module level\r\nconst CREATE_ACCOUNT = gql`\r\n\u00a0 \u00a0 mutation CreateAccount($input: AccountCreateInput!) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 uiapi {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 AccountCreate(input: $input) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Record {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Id\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Name { value }\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Type { value }\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 }\r\n`;\r\n\u00a0\r\nexport default class GraphqlMutationCreate extends LightningElement {\r\n\u00a0 \u00a0 isLoading = false;\r\n\u00a0 \u00a0 createdId\u00a0 = '';\r\n\u00a0 \u00a0 errorMsg \u00a0 = '';\r\n\u00a0\r\n\u00a0 \u00a0 async createAccount(name, type) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.isLoading = true;\r\n\u00a0 \u00a0 \u00a0 \u00a0 try {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ Note: returns { data, errors }, errors is an ARRAY\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const { data, errors } = await executeMutation(this, {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 query: CREATE_ACCOUNT,\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 variables: {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 input: {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Name: { value: name },\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Type: { value: type },\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 },\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 operationName: 'CreateAccount',\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 });\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if (errors?.length) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 this.errorMsg = errors.map(e =&gt; e.message).join(', ');\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return;\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 this.createdId = data?.uiapi?.AccountCreate?.Record?.Id;\r\n\u00a0 \u00a0 \u00a0 \u00a0 } finally {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 this.isLoading = false;\r\n\u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>graphqlMutationUpdate.js<\/strong><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\" title=\"graphqlMutationUpdate.js\">import { gql, executeMutation } from 'lightning\/graphql';\r\n\u00a0\r\nconst UPDATE_CONTACT = gql`\r\n\u00a0 \u00a0 mutation UpdateContact($id: ID!, $input: ContactUpdateInput!) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 uiapi {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ContactUpdate(id: $id, input: $input) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Record { Id\u00a0 FirstName { value }\u00a0 LastName { value }\u00a0 Email { value } }\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 }\r\n`;\r\n\u00a0\r\nasync updateContact(recordId, firstName, lastName, email) {\r\n\u00a0 \u00a0 const { data, errors } = await executeMutation(this, {\r\n\u00a0 \u00a0 \u00a0 \u00a0 query: UPDATE_CONTACT,\r\n\u00a0 \u00a0 \u00a0 \u00a0 variables: {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 id: recordId,\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 input: {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 FirstName: { value: firstName },\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 LastName:\u00a0 { value: lastName },\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Email: \u00a0 \u00a0 { value: email },\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 \u00a0 \u00a0 },\r\n\u00a0 \u00a0 \u00a0 \u00a0 operationName: 'UpdateContact',\r\n\u00a0 \u00a0 });\r\n\u00a0 \u00a0 if (!errors?.length) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 console.log('Updated:', data?.uiapi?.ContactUpdate?.Record?.Id);\r\n\u00a0 \u00a0 }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>graphqlMutationDelete.js<\/strong><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\" title=\"\u00a0 graphqlMutationDelete.js\">import { LightningElement, wire } from 'lwc';\r\nimport { gql, executeMutation, refreshGraphQL } from 'lightning\/graphql';\r\n\u00a0\r\nconst DELETE_CONTACT = gql`\r\n\u00a0 \u00a0 mutation DeleteContact($id: ID!) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 uiapi {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ContactDelete(id: $id) { Record { Id } }\r\n\u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 }\r\n`;\r\n\u00a0\r\nasync deleteContact(recordId) {\r\n\u00a0 \u00a0 const { errors } = await executeMutation(this, {\r\n\u00a0 \u00a0 \u00a0 \u00a0 query: DELETE_CONTACT,\r\n\u00a0 \u00a0 \u00a0 \u00a0 variables: { id: recordId },\r\n\u00a0 \u00a0 \u00a0 \u00a0 operationName: 'DeleteContact',\r\n\u00a0 \u00a0 });\r\n\u00a0 \u00a0 if (!errors?.length) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Refresh the @wire read query to reflect the deletion\r\n\u00a0 \u00a0 \u00a0 \u00a0 await refreshGraphQL(this.contactsWireResult);\r\n\u00a0 \u00a0 }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><b><i>errors (array) &#8211; not error (singular)<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400;\">executeMutation returns { data, errors } where errors is an array. Always check errors?.length. Child relationship fields are not supported in mutation response queries. See LWC Recipes PR #1083 for complete implementation with tests.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"3-TypeScript-Support-for-Base-Components\"><\/span><span style=\"font-weight: 400;\">3. TypeScript Support for Base Components<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">The TypeScript rollout for Lightning base components is now complete. Install @salesforce\/lightning-types to get IntelliSense, autocomplete, and compile-time error detection for every base component. Catch bugs at edit time, not after deployment.<\/span><\/p>\n<h4><span class=\"ez-toc-section\" id=\"Set-up-in-4-steps\"><\/span><span style=\"font-weight: 400;\">Set up in 4 steps:<\/span><span class=\"ez-toc-section-end\"><\/span><\/h4>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Step 1: <\/b><span style=\"font-weight: 400;\">Install: npm install &#8211;save-dev typescript @salesforce\/lightning-types<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Step 2: <\/b><span style=\"font-weight: 400;\">\u00a0Enable: Add &#8220;salesforcedx-vscode-lwc.typescript&#8221;: true to .vscode\/settings.json<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Step 3:<\/b><span style=\"font-weight: 400;\"> Compile: npx tsc &#8211;project .\/force-app\/main\/default\/lwc<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Step 4:<\/b><span style=\"font-weight: 400;\"> Deploy: sf project deploy start &#8211;source-dir force-app<\/span><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><strong>\u00a0 typeSafeForm.ts<\/strong><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\" title=\"\u00a0 typeSafeForm.ts\">import { LightningElement } from 'lwc';\r\nimport type {\r\n\u00a0 \u00a0 LightningInput,\r\n\u00a0 \u00a0 LightningButton,\r\n\u00a0 \u00a0 LightningCombobox,\r\n} from '@salesforce\/lightning-types';\r\n\u00a0\r\nexport default class TypeSafeForm extends LightningElement {\r\n\u00a0 \u00a0 firstName: string = '';\r\n\u00a0 \u00a0 lastName:\u00a0 string = '';\r\n\u00a0 \u00a0 status:\u00a0 \u00a0 string = '';\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ Cast event.target for full IntelliSense on .value, .validity, .label\r\n\u00a0 \u00a0 handleFirstNameChange(event: Event): void {\r\n\u00a0 \u00a0 \u00a0 \u00a0 const input = event.target as LightningInput;\r\n\u00a0 \u00a0 \u00a0 \u00a0 if (input.validity.valid) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 this.firstName = input.value;\r\n\u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 }\r\n\u00a0\r\n\u00a0 \u00a0 handleLastNameChange(event: Event): void {\r\n\u00a0 \u00a0 \u00a0 \u00a0 const input = event.target as LightningInput;\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.lastName = input.value;\r\n\u00a0 \u00a0 }\r\n\u00a0\r\n\u00a0 \u00a0 handleSubmit(event: Event): void {\r\n\u00a0 \u00a0 \u00a0 \u00a0 const btn = event.target as LightningButton;\r\n\u00a0 \u00a0 \u00a0 \u00a0 console.log('Button label:', btn.label); \u00a0 \/\/ fully typed, no 'any'\r\n\u00a0 \u00a0 }\r\n\u00a0\r\n\u00a0 \u00a0 handleStatusChange(event: Event): void {\r\n\u00a0 \u00a0 \u00a0 \u00a0 const combo = event.target as LightningCombobox;\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.status = combo.value;\r\n\u00a0 \u00a0 }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><b><i>Pro tip<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400;\">The platform stores only JavaScript .ts files that are compiled locally, and the .js output is deployed. Never ship uncompiled TypeScript to a package. If you have custom type stubs for base components, switch to @salesforce\/lightning-types for better coverage.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"4-Navigate-to-Flows-from-LWC\"><\/span><span style=\"font-weight: 400;\">4. Navigate to Flows from LWC<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Launching a flow from a component now takes one navigate call. Use the standard__flow PageReference type with the flow&#8217;s API name, and pass input data through the state object, it maps directly to the flow&#8217;s input variables.<\/span><\/p>\n<h3><\/h3>\n<p><strong>navToFlow.js, LWC Recipes PR #1082<\/strong><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\" title=\"navToFlow.js, LWC Recipes PR #1082\">import { LightningElement, api } from 'lwc';\r\nimport { NavigationMixin } from 'lightning\/navigation';\r\n\u00a0\r\nexport default class NavToFlow extends NavigationMixin(LightningElement) {\r\n\u00a0 \u00a0 @api recordId;\r\n\u00a0 \u00a0 @api flowApiName = 'Contact_Onboarding_Flow';\r\n\u00a0\r\n\u00a0 \u00a0 handleLaunchFlow() {\r\n\u00a0 \u00a0 \u00a0 \u00a0 this[NavigationMixin.Navigate]({\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 type: 'standard__flow',\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 attributes: {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 flowApiName: this.flowApiName,\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 },\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 state: {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ state keys prefixed with flow__ become flow input variables\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'flow__contactId': this.recordId,\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'flow__source':\u00a0 \u00a0 'LWC',\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 \u00a0 \u00a0 });\r\n\u00a0 \u00a0 }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"5-Error-Console\"><\/span><span style=\"font-weight: 400;\">5. Error Console\u00a0<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Tired of red-box popups interrupting your testing? The Error Console silently logs non-fatal errors to a dedicated panel you can review whenever you want. Fatal errors that do require a pop-up are also captured here for a full debug history.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">Enable it at: Setup &gt; User Interface &gt; Advanced Settings &gt; &#8216;Use Error Console for error reporting in Lightning Experience&#8217;.<\/span><\/p>\n<figure id=\"attachment_16700\" aria-describedby=\"caption-attachment-16700\" style=\"width: 966px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"size-full wp-image-16700\" src=\"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image5.png\" alt=\"Error Console, non-fatal errors logged silently, fatal errors captured for full history\u00a0 |\u00a0 Source: Salesforce Developer Blog\" width=\"966\" height=\"460\" srcset=\"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image5.png 966w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image5-768x366.png 768w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image5-640x305.png 640w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image5-400x190.png 400w\" sizes=\"(max-width: 966px) 100vw, 966px\" \/><figcaption id=\"caption-attachment-16700\" class=\"wp-caption-text\">Error Console, non-fatal errors logged silently, fatal errors captured for full history\u00a0 |\u00a0 Source: Salesforce Developer Blog<\/figcaption><\/figure>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"6-Complex-Template-Expressions\"><\/span><span style=\"font-weight: 400;\">6. Complex Template Expressions<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Write JavaScript expressions directly in LWC templates, template literals, ternary operators, optional chaining, null coalescing, array methods, and inline event handlers. No more boilerplate getter methods for simple display logic.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><strong>Before Spring &#8217;26<\/strong><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\" title=\"Before Spring '26\">&lt;!-- BEFORE, getter methods required for all display logic --&gt;\r\n\u00a0\r\n\/\/ contactCard.js\r\nget fullName()\u00a0 \u00a0 { return `${this.firstName} ${this.lastName}`; }\r\nget statusLabel() { return this.isActive ? 'Active' : 'Inactive'; }\r\nget stockCount()\u00a0 { return this.items.filter(i =&gt; i.inStock).length; }\r\n\u00a0\r\n\/\/ contactCard.html\r\n&lt;p&gt;{fullName}&lt;\/p&gt;\r\n&lt;span&gt;{statusLabel}&lt;\/span&gt;\r\n&lt;p&gt;{stockCount} in stock&lt;\/p&gt;<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>\u00a0 After Spring &#8217;26 Complex Template Expressions<\/strong><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\" title=\"\u00a0 After, Spring '26 Complex Template Expressions\">&lt;!-- AFTER, inline expressions, no getters needed --&gt;\r\n\u00a0\r\n&lt;!-- Template literal --&gt;\r\n&lt;p&gt;{`Hello, ${firstName} ${lastName}!`}&lt;\/p&gt;\r\n\u00a0\r\n&lt;!-- Ternary --&gt;\r\n&lt;span&gt;{isActive ? 'Active' : 'Inactive'}&lt;\/span&gt;\r\n\u00a0\r\n&lt;!-- Array method --&gt;\r\n&lt;p&gt;{items.filter(item =&gt; item.inStock).length} in stock&lt;\/p&gt;\r\n\u00a0\r\n&lt;!-- Optional chaining + null coalescing --&gt;\r\n&lt;p&gt;Theme: {user?.profile?.theme ?? 'default'}&lt;\/p&gt;\r\n\u00a0\r\n&lt;!-- Inline handler --&gt;\r\n&lt;lightning-button label=\"Add\" onclick={()=&gt;{ quantity++ }}&gt;&lt;\/lightning-button&gt;<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><b><i>Beta: use in the sandbox first<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400;\">Complex Template Expressions are subject to Salesforce Beta Services Terms. The feature direction is committed, but the syntax may change before GA. Test in sandbox and developer orgs before any production rollout.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"7-Lightning-Empty-State-Illustration-Component\"><\/span><span style=\"font-weight: 400;\">7. Lightning Empty State &amp; Illustration Component<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Two new base components deliver SLDS-compliant empty states with zero custom CSS. Both automatically adapt to dark mode themes. Drop them in, and they look polished immediately.<\/span><\/p>\n<p>&nbsp;<\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\">&lt;!-- Full empty state with illustration, title, description, and CTA --&gt;\r\n&lt;lightning-empty-state\r\n\u00a0 \u00a0 illustration-name=\"cart:noitems\"\r\n\u00a0 \u00a0 title=\"No Records Found\"&gt;\r\n\u00a0\r\n\u00a0 \u00a0 &lt;p slot=\"description\"&gt;\r\n\u00a0 \u00a0 \u00a0 \u00a0 No contacts match your current filters.\r\n\u00a0 \u00a0 &lt;\/p&gt;\r\n\u00a0\r\n\u00a0 \u00a0 &lt;lightning-button\r\n\u00a0 \u00a0 \u00a0 \u00a0 slot=\"actions\"\r\n\u00a0 \u00a0 \u00a0 \u00a0 label=\"Create New Contact\"\r\n\u00a0 \u00a0 \u00a0 \u00a0 onclick={handleCreate}&gt;\r\n\u00a0 \u00a0 &lt;\/lightning-button&gt;\r\n\u00a0\r\n&lt;\/lightning-empty-state&gt;\r\n\u00a0\r\n&lt;!-- Illustration only, no surrounding text needed --&gt;\r\n&lt;lightning-illustration illustration-name=\"access:request\" size=\"large\"&gt;\r\n&lt;\/lightning-illustration&gt;\r\n\u00a0\r\n&lt;!-- Available names: cart:noitems, access:request, empty:desert,\r\n\u00a0 \u00a0 error:pageNotFound, and more from the SLDS illustration library --&gt;<\/pre>\n<p>&nbsp;<\/p>\n<figure id=\"attachment_16701\" aria-describedby=\"caption-attachment-16701\" style=\"width: 700px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"size-full wp-image-16701\" src=\"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image2.png\" alt=\"lightning-empty-state, SLDS illustration + title + description + CTA, auto dark-mode\u00a0 |\u00a0 Source: Salesforce Developer Blog\" width=\"700\" height=\"520\" srcset=\"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image2.png 700w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image2-640x475.png 640w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image2-400x297.png 400w\" sizes=\"(max-width: 700px) 100vw, 700px\" \/><figcaption id=\"caption-attachment-16701\" class=\"wp-caption-text\">lightning-empty-state, SLDS illustration + title + description + CTA, auto dark-mode\u00a0 |\u00a0 Source: Salesforce Developer Blog<\/figcaption><\/figure>\n<p>&nbsp;<\/p>\n<h2><span class=\"ez-toc-section\" id=\"-Apex-Updates-in-Spring-26\"><\/span><span style=\"font-weight: 400;\">\u00a0Apex Updates in Spring &#8217;26<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Apex gets three meaningful improvements this release: Cursors move to GA for large-dataset processing, RunRelevantTests speeds up CI\/CD deployments, and a new ConnectApi method eliminates callouts for picklist data.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"1-Apex-Cursors-Now-Generally-Available\"><\/span><span style=\"font-weight: 400;\">1. Apex Cursors: Now Generally Available<\/span><b>\u00a0<\/b><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Apex Cursors let you work with large SOQL result sets in manageable chunks without the rigidity of Batch Apex. Create a cursor once, the result set is cached server-side, then fetch records from any position, forward or backward. Ideal for processing millions of records without re-running the query.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><b><i>Basic usage<\/i><\/b><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\">Database.Cursor locator = Database.getCursor(\r\n\u00a0 \u00a0 'SELECT Id, Name, Status__c FROM Case WHERE Status__c = \\'Open\\' ORDER BY CreatedDate'\r\n);\r\n\u00a0\r\nInteger total = locator.getNumRecords();\r\n\u00a0\r\n\/\/ Fetch any chunk from any offset, bidirectional\r\nList&lt;Case&gt; first\u00a0 = locator.fetch(0, 200);\r\nList&lt;Case&gt; second = locator.fetch(200, 200);\r\nList&lt;Case&gt; last \u00a0 = locator.fetch(total - 50, 50);\r\n\u00a0\r\n\/\/ Track governor limit usage\r\nSystem.debug('Cursor rows used: ' + Limits.getApexCursorRows());<\/pre>\n<h4><\/h4>\n<h4><span class=\"ez-toc-section\" id=\"Pattern-1-Queueable-chaining-for-millions-of-records\"><\/span><span style=\"font-weight: 400;\">Pattern 1: Queueable chaining for millions of records<\/span><span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p><span style=\"font-weight: 400;\">Cursors are serialisable; they survive intact between Queueable job executions, so you can chain through arbitrarily large datasets without ever re-running the query.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><strong>\u00a0 QueryChunkingQueueable.cls<\/strong><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\" title=\"\u00a0 QueryChunkingQueueable.cls\">public class QueryChunkingQueueable implements Queueable {\r\n\u00a0\r\n\u00a0 \u00a0 private Database.Cursor locator;\r\n\u00a0 \u00a0 private Integer \u00a0 \u00a0 \u00a0 \u00a0 position;\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ Entry point, create the cursor once, it is cached server-side\r\n\u00a0 \u00a0 public QueryChunkingQueueable() {\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.locator\u00a0 = Database.getCursor(\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'SELECT Id FROM Contact WHERE LastActivityDate = LAST_N_DAYS:400'\r\n\u00a0 \u00a0 \u00a0 \u00a0 );\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.position = 0;\r\n\u00a0 \u00a0 }\r\n\u00a0\r\n\u00a0 \u00a0 public void execute(QueueableContext ctx) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Chunk size is flexible, Batch Apex fixes it at job start\r\n\u00a0 \u00a0 \u00a0 \u00a0 List&lt;Contact&gt; scope = locator.fetch(position, 200);\r\n\u00a0 \u00a0 \u00a0 \u00a0 position += scope.size();\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 List&lt;Contact&gt; toUpdate = new List&lt;Contact&gt;();\r\n\u00a0 \u00a0 \u00a0 \u00a0 for (Contact c : scope) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 c.Description = 'Archived: ' + Date.today();\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 toUpdate.add(c);\r\n\u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 \u00a0 \u00a0 if (!toUpdate.isEmpty()) update toUpdate;\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Re-enqueue while records remain, chains automatically\r\n\u00a0 \u00a0 \u00a0 \u00a0 if (position &lt; locator.getNumRecords()) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 System.enqueueJob(this);\r\n\u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 }\r\n\u00a0\r\n\u00a0 \u00a0 public static void start() {\r\n\u00a0 \u00a0 \u00a0 \u00a0 System.enqueueJob(new QueryChunkingQueueable());\r\n\u00a0 \u00a0 }\r\n}<\/pre>\n<h4><\/h4>\n<h4><span class=\"ez-toc-section\" id=\"Pattern-2-PaginationCursor-for-LWC-page-navigation\"><\/span><span style=\"font-weight: 400;\">Pattern 2: PaginationCursor for LWC page navigation<\/span><span class=\"ez-toc-section-end\"><\/span><\/h4>\n<p><span style=\"font-weight: 400;\">PaginationCursor is a variant built for user-facing lists. It is @AuraEnabled-serialisable, pass it between your LWC and Apex for smooth server-side paging with no OFFSET queries.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><strong>PaginationController.cls<\/strong><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\" title=\"PaginationController.cls\">public with sharing class PaginationController {\r\n\u00a0\r\n\u00a0 \u00a0 public class PageResult {\r\n\u00a0 \u00a0 \u00a0 \u00a0 @AuraEnabled public List&lt;Contact&gt;\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 records;\r\n\u00a0 \u00a0 \u00a0 \u00a0 @AuraEnabled public Database.PaginationCursor cursor;\r\n\u00a0 \u00a0 \u00a0 \u00a0 @AuraEnabled public Integer\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 total;\r\n\u00a0 \u00a0 \u00a0 \u00a0 @AuraEnabled public Boolean\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 hasMore;\r\n\u00a0 \u00a0 }\r\n\u00a0\r\n\u00a0 \u00a0 @AuraEnabled(cacheable=false)\r\n\u00a0 \u00a0 public static PageResult getFirstPage(Integer pageSize) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 Database.PaginationCursor cursor = Database.getPaginationCursor(\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 'SELECT Id, FirstName, LastName, Email FROM Contact ORDER BY LastName'\r\n\u00a0 \u00a0 \u00a0 \u00a0 );\r\n\u00a0 \u00a0 \u00a0 \u00a0 return build(cursor, pageSize);\r\n\u00a0 \u00a0 }\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ Reuse the cursor, no new SOQL issued on the server\r\n\u00a0 \u00a0 @AuraEnabled(cacheable=false)\r\n\u00a0 \u00a0 public static PageResult getNextPage(Database.PaginationCursor cursor, Integer pageSize) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 return build(cursor, pageSize);\r\n\u00a0 \u00a0 }\r\n\u00a0\r\n\u00a0 \u00a0 private static PageResult build(Database.PaginationCursor cursor, Integer pageSize) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 PageResult r = new PageResult();\r\n\u00a0 \u00a0 \u00a0 \u00a0 r.records\u00a0 = cursor.fetchPage(pageSize);\r\n\u00a0 \u00a0 \u00a0 \u00a0 r.cursor \u00a0 = cursor;\r\n\u00a0 \u00a0 \u00a0 \u00a0 r.total\u00a0 \u00a0 = cursor.getNumRecords();\r\n\u00a0 \u00a0 \u00a0 \u00a0 r.hasMore\u00a0 = cursor.getNumRecords() &gt; 0;\r\n\u00a0 \u00a0 \u00a0 \u00a0 return r;\r\n\u00a0 \u00a0 }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><strong>paginatedList.js<\/strong><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\" title=\"paginatedList.js\">import { LightningElement, track } from 'lwc';\r\nimport getFirstPage from '@salesforce\/apex\/PaginationController.getFirstPage';\r\nimport getNextPage\u00a0 from '@salesforce\/apex\/PaginationController.getNextPage';\r\n\u00a0\r\nconst PAGE_SIZE = 20;\r\n\u00a0\r\nexport default class PaginatedList extends LightningElement {\r\n\u00a0 \u00a0 @track records\u00a0 = [];\r\n\u00a0 \u00a0 @track hasMore\u00a0 = false;\r\n\u00a0 \u00a0 cursor\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 = null;\r\n\u00a0 \u00a0 total \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 = 0;\r\n\u00a0\r\n\u00a0 \u00a0 async connectedCallback() {\r\n\u00a0 \u00a0 \u00a0 \u00a0 const r = await getFirstPage({ pageSize: PAGE_SIZE });\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.records = r.records;\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.cursor\u00a0 = r.cursor; \u00a0 \/\/ serialised cursor returned to Apex on next call\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.total \u00a0 = r.total;\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.hasMore = r.hasMore;\r\n\u00a0 \u00a0 }\r\n\u00a0\r\n\u00a0 \u00a0 async loadNextPage() {\r\n\u00a0 \u00a0 \u00a0 \u00a0 if (!this.hasMore) return;\r\n\u00a0 \u00a0 \u00a0 \u00a0 const r = await getNextPage({ cursor: this.cursor, pageSize: PAGE_SIZE });\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.records = [...this.records, ...r.records];\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.cursor\u00a0 = r.cursor;\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.hasMore = r.hasMore;\r\n\u00a0 \u00a0 }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Cursor-vs-Batch-Apex-vs-PaginationCursor\"><\/span><span style=\"font-weight: 400;\">Cursor vs Batch Apex vs PaginationCursor<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n<table id=\"tablepress-198\" class=\"tablepress tablepress-id-198\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\">Dimension<\/th><th class=\"column-2\">Batch Apex<\/th><th class=\"column-3\">Cursor + Queueable<\/th><th class=\"column-4\">PaginationCursor<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\">Max records<\/td><td class=\"column-2\">50M<\/td><td class=\"column-3\">50M per cursor<\/td><td class=\"column-4\">100K per cursor<\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\">Query re-execution<\/td><td class=\"column-2\">Yes (per chunk)<\/td><td class=\"column-3\">No, server-cached<\/td><td class=\"column-4\">No, server-cached<\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\">Direction<\/td><td class=\"column-2\">Forward only<\/td><td class=\"column-3\">Bidirectional<\/td><td class=\"column-4\">Bidirectional<\/td>\n<\/tr>\n<tr class=\"row-5\">\n\t<td class=\"column-1\">Chunk size<\/td><td class=\"column-2\">Fixed at job start<\/td><td class=\"column-3\">Flexible per fetch()<\/td><td class=\"column-4\">Fixed per fetchPage()<\/td>\n<\/tr>\n<tr class=\"row-6\">\n\t<td class=\"column-1\">LWC pagination<\/td><td class=\"column-2\">Complex (polling)<\/td><td class=\"column-3\">@AuraEnabled serialisable<\/td><td class=\"column-4\">@AuraEnabled serialisable<\/td>\n<\/tr>\n<tr class=\"row-7\">\n\t<td class=\"column-1\">Best for<\/td><td class=\"column-2\">Scheduled DML-heavy jobs<\/td><td class=\"column-3\">Async large-volume processing<\/td><td class=\"column-4\">User-facing list pagination<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-198 from cache -->\n<p>&nbsp;<\/p>\n<p><b><i>Cursor governor limits<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400;\">Cursors help you use limits smarter; they don&#8217;t bypass them. Each fetch() counts against the SOQL row limit. Max: 50M records\/cursor, 10K cursor instances\/24hrs, 200K PaginationCursor instances\/24hrs.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"2-RunRelevantTests-Faster-Deployments\"><\/span><span style=\"font-weight: 400;\">2. RunRelevantTests: Faster Deployments<\/span><b>\u00a0<\/b><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">A new deployment test level that analyses the dependency graph of your payload and runs only the tests relevant to the changed code. For large organizations with thousands of test methods, this can dramatically reduce CI\/CD deployment time.<\/span><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\"># Use RunRelevantTests, dependency analysis is automatic\r\nsf project deploy start --test-level RunRelevantTests\r\n\u00a0\r\n# Scoped to a specific file\r\nsf project deploy start \\\r\n\u00a0 --source-dir force-app\/main\/default\/classes\/OrderService.cls \\\r\n\u00a0 --test-level RunRelevantTests<\/pre>\n<p>&nbsp;<\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\">\/\/ @IsTest(testFor), link a test to specific components.\r\n\/\/ Only runs when OrderService or OrderTrigger is in the deployment.\r\n@IsTest(testFor='ApexClass:OrderService,ApexTrigger:OrderTrigger')\r\npublic class OrderServiceTest {\r\n\u00a0 \u00a0 @isTest static void testOrderCreation() { \/* ... *\/ }\r\n}\r\n\u00a0\r\n\/\/ @IsTest(critical=true), this test ALWAYS runs regardless of payload.\r\n\/\/ Use for smoke tests, compliance checks, cross-system integration tests.\r\n@IsTest(critical=true)\r\npublic class CriticalSmokeTest {\r\n\u00a0 \u00a0 @isTest static void runAlways() { \/* ... *\/ }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"3-Picklist-Values-by-Record-Type-New-Apex-Method\"><\/span><span style=\"font-weight: 400;\">3. Picklist Values by Record Type: New Apex Method<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Retrieving record-type-specific picklist values in Apex used to require UI API callouts. The new ConnectApi.RecordUi.getPicklistValuesByRecordType() method eliminates that; one native Apex call returns all picklist fields for a given record type, including dependent relationships and default values.<\/span><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true \">@AuraEnabled(cacheable=true)\r\npublic static Map&lt;String, Object&gt; getPicklistValues(\r\n\u00a0 \u00a0 String objectApiName,\r\n\u00a0 \u00a0 String recordTypeId\r\n) {\r\n\u00a0 \u00a0 ConnectApi.PicklistValuesCollection col =\r\n\u00a0 \u00a0 \u00a0 \u00a0 ConnectApi.RecordUi.getPicklistValuesByRecordType(\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 objectApiName,\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 recordTypeId\r\n\u00a0 \u00a0 \u00a0 \u00a0 );\r\n\u00a0\r\n\u00a0 \u00a0 Map&lt;String, Object&gt; result = new Map&lt;String, Object&gt;();\r\n\u00a0 \u00a0 for (String field : col.picklistFieldValues.keySet()) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 ConnectApi.PicklistValuesRepresentation pvr = col.picklistFieldValues.get(field);\r\n\u00a0 \u00a0 \u00a0 \u00a0 List&lt;String&gt; vals = new List&lt;String&gt;();\r\n\u00a0 \u00a0 \u00a0 \u00a0 for (ConnectApi.PicklistValueRepresentation pv : pvr.values) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 vals.add(pv.value);\r\n\u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 \u00a0 \u00a0 result.put(field, vals);\r\n\u00a0 \u00a0 }\r\n\u00a0 \u00a0 return result;\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"4-BlobtoPdf-New-Rendering-Engine\"><\/span><span style=\"font-weight: 400;\">4. Blob.toPdf(): New Rendering Engine<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">\u00a0Blob.toPdf() now uses the same rendering engine as Visualforce PDFs, consistent output, expanded font support, and full CJK (Chinese, Japanese, Korean), Thai, and Arabic character rendering. The API is unchanged; the results are better.<\/span><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\">public class CertificateGenerator {\r\n\u00a0 \u00a0 public static Blob generate(String recipient, String course, Date completed) {\r\n\u00a0 \u00a0 \u00a0 \u00a0 String html = '&lt;!DOCTYPE html&gt;&lt;html&gt;&lt;head&gt;'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + '&lt;meta charset=\"UTF-8\"&gt;'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + '&lt;style&gt;'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + 'body { font-family: Arial, sans-serif; margin: 60px; }'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ Backward compat: if your PDFs use old serif font, add:\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ font-family: serif;\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + '.cert { padding: 60px; border: 3px solid #032D60; }'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + 'h1 { color: #032D60; text-align: center; }'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + '.name { color: #00A1E0; font-size: 28px; text-align: center; }'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + '&lt;\/style&gt;&lt;\/head&gt;&lt;body&gt;&lt;div class=\"cert\"&gt;'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + '&lt;h1&gt;Certificate of Completion&lt;\/h1&gt;'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + '&lt;p class=\"name\"&gt;' + recipient + '&lt;\/p&gt;'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + '&lt;p style=\"text-align:center\"&gt;Completed: ' + course + '&lt;\/p&gt;'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ Spring '26 engine renders CJK \/ Arabic \/ Thai natively\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + '&lt;p style=\"text-align:center\"&gt;\u5b8c\u4e86 \u00b7 \u0645\u0643\u062a\u0645\u0644 \u00b7 \u0e40\u0e2a\u0e23\u0e47\u0e08&lt;\/p&gt;'\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 + '&lt;\/div&gt;&lt;\/body&gt;&lt;\/html&gt;';\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 return Blob.toPdf(html); \u00a0 \/\/ same API, upgraded engine under the hood\r\n\u00a0 \u00a0 }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><b><i>Check existing PDFs before Summer &#8217;26<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400;\">If your PDFs rely on the old serif default font, line breaks and spacing may change. Add font-family: serif to maintain backward compatibility. Review via Setup &gt; Release Updates and test in the sandbox before the Summer &#8217;26 enforcement date.<\/span><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Agentforce-Developer-Features\"><\/span><span style=\"font-weight: 400;\">Agentforce Developer Features<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Spring &#8217;26 brings the most significant Agentforce developer tooling update to date, a rebuilt Builder interface, a new DSL for authoring agent logic, a spreadsheet-style testing environment, and pro-code VS Code tooling. Updates ship monthly within the release window, so watch the release notes.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"1-New-Agentforce-Builder-Canvas-Script-Views\"><\/span><span style=\"font-weight: 400;\">1.\u00a0 New Agentforce Builder: Canvas &amp; Script Views<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">The new Agentforce Builder replaces the previous interface with a text editor-inspired IDE, complete with a file explorer, two distinct working modes, and an upgraded graph-based Atlas Reasoning Engine that lets you mix deterministic logic with natural language prompts.<\/span><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Canvas view: <\/b><span style=\"font-weight: 400;\">Drag-and-drop visual editor for assembling if-then logic flows, action sequences, and topic transitions.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Script view: <\/b><span style=\"font-weight: 400;\">Author Agent Script DSL directly in a text editor, version-controllable and diffable.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Deterministic logic: <\/b><span style=\"font-weight: 400;\">Chain actions in a guaranteed sequence. Control topic transitions precisely, without relying solely on LLM judgment.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Deep debug:<\/b><span style=\"font-weight: 400;\"> Trace + reasoning summary for every agent message. See exactly why the agent took each action.<\/span><\/li>\n<\/ul>\n<figure id=\"attachment_16703\" aria-describedby=\"caption-attachment-16703\" style=\"width: 1000px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"size-full wp-image-16703\" src=\"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image3.png\" alt=\"Agentforce Builder: Canvas mode with visual logic flow and Atlas Reasoning Engine\u00a0 |\u00a0 Salesforce Developer Blog\" width=\"1000\" height=\"580\" srcset=\"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image3.png 1000w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image3-768x445.png 768w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image3-640x371.png 640w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image3-400x232.png 400w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><figcaption id=\"caption-attachment-16703\" class=\"wp-caption-text\">Agentforce Builder: Canvas mode with visual logic flow and Atlas Reasoning Engine\u00a0 |\u00a0 Salesforce Developer Blog<\/figcaption><\/figure>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"2-Agent-Script-DSL\"><\/span><span style=\"font-weight: 400;\">2. Agent Script DSL<\/span><b>\u00a0<\/b><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Agent Script is a new DSL that combines natural language instructions with deterministic code-like constructs, if-else conditions, variable bindings, and action sequencing. You curate exactly what instructions and state variables the LLM receives, giving it a high-signal prompt and predictable behavior.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><strong>escalation.agent-script<\/strong><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\"># Agent Script, Escalation Handler\r\n# Mixes natural language with deterministic conditionals.\r\n# LLM handles conversation; Agent Script enforces business rules.\r\n\u00a0\r\nagent: EscalationAgent\r\ndescription: Handles customer service escalation requests\r\n\u00a0\r\ntopics:\r\n\u00a0 - name: HandleEscalation\r\n\u00a0 \u00a0 instructions: |\r\n\u00a0 \u00a0 \u00a0 Greet the customer and acknowledge their frustration.\r\n\u00a0 \u00a0 \u00a0 Use calm, empathetic language throughout.\r\n\u00a0 \u00a0 \u00a0 Never promise refunds, only promise follow-up.\r\n\u00a0\r\n\u00a0 \u00a0 # These conditionals always execute, not left to LLM judgment\r\n\u00a0 \u00a0 conditions:\r\n\u00a0 \u00a0 \u00a0 - if: $context.caseType == 'Billing'\r\n\u00a0 \u00a0 \u00a0 \u00a0 then:\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 action: TransferToBillingTeam\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 message: 'Connecting you to our billing specialists now.'\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 - if: $context.priority == 'Critical'\r\n\u00a0 \u00a0 \u00a0 \u00a0 then:\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 action: EscalateToManager\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 variables:\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urgencyLevel: 'HIGH'\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 - else:\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 action: CreateCaseAndFollowUp\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 instructions: |\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Summarise the issue clearly for the case notes.\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Set expectations: 24-hour follow-up timeline.<\/pre>\n<p>&nbsp;<\/p>\n<p><b><i>Why Agent Script?<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400;\">Unlike freeform system prompts, Agent Script is version-controllable, diffable, and reviewable in pull requests. By curating the state variables and instructions the LLM sees, you reduce ambiguity and hallucinations. Explore the Agent Script Recipes sample app at <\/span><a href=\"http:\/\/developer.salesforce.com\/sample-apps\/agent-script-recipes\"><span style=\"font-weight: 400;\">developer.salesforce.com\/sample-apps\/agent-script-recipes<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"3-Agent-Grid\"><\/span><span style=\"font-weight: 400;\">3. Agent Grid<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Agentforce Grid is a spreadsheet-like environment for testing AI workflows against real CRM data. Every row is a CRM record, every column is an agent action, every cell shows immediate AI output. No deployment cycle needed to validate logic changes.<\/span><\/p>\n<figure id=\"attachment_16704\" aria-describedby=\"caption-attachment-16704\" style=\"width: 1000px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"size-full wp-image-16704\" src=\"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image1.png\" alt=\"Agentforce Grid: rows are CRM records, columns are agent actions, cells show instant AI output\u00a0 |\u00a0 Salesforce Developer Blog\" width=\"1000\" height=\"540\" srcset=\"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image1.png 1000w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image1-768x415.png 768w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image1-640x346.png 640w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image1-400x216.png 400w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><figcaption id=\"caption-attachment-16704\" class=\"wp-caption-text\">Agentforce Grid: rows are CRM records, columns are agent actions, cells show instant AI output\u00a0 |\u00a0 Salesforce Developer Blog<\/figcaption><\/figure>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"4-Agentforce-DX-Pro-Code-in-VS-Code\"><\/span><span style=\"font-weight: 400;\">4. Agentforce DX: Pro-Code in VS Code<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Agentforce DX is the pro-code equivalent of the Builder UI. Build, test, and deploy agents in VS Code and the Salesforce CLI without context switching. Retrieve an admin-built agent from Agentforce Builder, pull it locally, and refine it with complex logic.<\/span><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Language Server:<\/b><span style=\"font-weight: 400;\"> Syntax highlighting, red squiggles for errors, internal validation, and outline support for Agent Script files.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Simulated preview: <\/b><span style=\"font-weight: 400;\">Test agent logic with mocked actions. Fast iteration, no org resources consumed.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Live preview:<\/b><span style=\"font-weight: 400;\"> Connect to real Apex, flows, and org data for end-to-end testing.<\/span><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<figure id=\"attachment_16705\" aria-describedby=\"caption-attachment-16705\" style=\"width: 1000px\" class=\"wp-caption aligncenter\"><img decoding=\"async\" class=\"size-full wp-image-16705\" src=\"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image4.png\" alt=\"Agentforce DX in VS Code: Agent Script editor with language server + Agent Preview\u00a0 |\u00a0 Salesforce Developer Blog\" width=\"1000\" height=\"560\" srcset=\"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image4.png 1000w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image4-768x430.png 768w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image4-640x358.png 640w, https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image4-400x224.png 400w\" sizes=\"(max-width: 1000px) 100vw, 1000px\" \/><figcaption id=\"caption-attachment-16705\" class=\"wp-caption-text\">Agentforce DX in VS Code: Agent Script editor with language server + Agent Preview\u00a0 |\u00a0 Salesforce Developer Blog<\/figcaption><\/figure>\n<p>&nbsp;<\/p>\n<h2><span class=\"ez-toc-section\" id=\"5-Agentforce-Vibes-AI-Developer-Tooling\"><\/span><span style=\"font-weight: 400;\">5. Agentforce Vibes: AI Developer Tooling<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Agentforce Vibes is an AI-powered developer assistant available as a VS Code extension and in the Agentforce Vibes IDE. Spring &#8217;26 delivers the improvements from versions 3.3.0 through 3.8.0, smarter planning, better context management, and a streamlined MCP experience.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"1-deep-planning-Structured-Complex-Workflows\"><\/span><span style=\"font-weight: 400;\">1. \/deep-planning, Structured Complex Workflows<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Type \/deep-planning in the Agentforce Vibes chat to invoke a structured four-step approach for complex tasks:<\/span><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Scan: <\/b><span style=\"font-weight: 400;\">Agent scans your codebase for relevant context and existing patterns.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Clarify: <\/b><span style=\"font-weight: 400;\">Agent asks targeted questions before writing any code.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Plan:<\/b><span style=\"font-weight: 400;\"> A comprehensive implementation plan is generated for your review.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Execute:<\/b><span style=\"font-weight: 400;\"> Task launches with all context loaded. A persistent Focus Chain keeps the agent on target across context resets.<\/span><\/li>\n<\/ul>\n<h3><span class=\"ez-toc-section\" id=\"2-MCP-Auto-Approval-Performance\"><\/span><span style=\"font-weight: 400;\">2. MCP Auto-Approval &amp; Performance<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Auto-approved: All read-only Salesforce DX MCP server tools, no more prompts for safe queries.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Still requires approval: All write operations, insert, update, delete, and deploy.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Performance: Toggling auto-approve no longer triggers server reconnections.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">UX: MCP tab renamed from &#8220;Installed&#8221; to &#8220;Configure&#8221;.<\/span><\/li>\n<\/ul>\n<h2><span class=\"ez-toc-section\" id=\"Salesforce-CLI-Updates\"><\/span><span style=\"font-weight: 400;\">Salesforce CLI Updates<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Spring &#8217;26 adds three notable CLI improvements: unified logic testing, package source retrieval, and quality-of-life improvements for login timeouts and test polling.<\/span><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true \"># Unified Logic Testing (Beta), run Apex + Flow tests in one request\r\nsf apex run test --test-level RunAllTestsInOrg --unified-logic-testing\r\n\u00a0\r\n# Retrieve 2GP or unlocked package source metadata locally\r\nsf package version retrieve \\\r\n\u00a0 --package 04tXXXXXXXXXXXXXXX \\\r\n\u00a0 --output-dir .\/retrieved-package \\\r\n\u00a0 --target-dev-hub devhub@example.com\r\n\u00a0\r\n# Set custom OAuth login timeout (prevents indefinite hang)\r\nexport SF_WEB_OAUTH_SERVER_TIMEOUT=180000 \u00a0 # 3 minutes in milliseconds\r\n\u00a0\r\n# Adjust test result polling interval to reduce API calls\r\nsf apex run test \\\r\n\u00a0 --class-names MyClassTest \\\r\n\u00a0 --poll-interval 10 \\\r\n\u00a0 --target-org my-org<\/pre>\n<p>&nbsp;<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Data-360-Monthly-Updates\"><\/span><span style=\"font-weight: 400;\">Data 360 Monthly Updates<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Data 360 ships on a monthly cadence. The headline addition for developers in this release is the new ConnectApi.CDPQuery methods for querying data graphs directly from Apex.<\/span><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true\">\/\/ Query a data graph by record ID\r\nConnectApi.CdpQueryResult byId =\r\n\u00a0 \u00a0 ConnectApi.CdpQuery.getDataGraphData(\r\n\u00a0 \u00a0 \u00a0 \u00a0 'myDataspace', \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ dataspace API name\r\n\u00a0 \u00a0 \u00a0 \u00a0 'UnifiedIndividual__dlm',\u00a0 \/\/ data model object\r\n\u00a0 \u00a0 \u00a0 \u00a0 '001Ws000001234' \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ record ID\r\n\u00a0 \u00a0 );\r\n\u00a0\r\n\/\/ Query by lookup key (e.g. an email address)\r\nConnectApi.CdpQueryResult byKey =\r\n\u00a0 \u00a0 ConnectApi.CdpQuery.getDataGraphData(\r\n\u00a0 \u00a0 \u00a0 \u00a0 'myDataspace',\r\n\u00a0 \u00a0 \u00a0 \u00a0 'UnifiedIndividual__dlm',\r\n\u00a0 \u00a0 \u00a0 \u00a0 'email',\r\n\u00a0 \u00a0 \u00a0 \u00a0 'user@example.com'\r\n\u00a0 \u00a0 );\r\n\u00a0\r\n\/\/ Get data graph metadata and schema\r\nConnectApi.DataGraphMetadata meta =\r\n\u00a0 \u00a0 ConnectApi.CdpQuery.getDataGraphMetadata(\r\n\u00a0 \u00a0 \u00a0 \u00a0 'myDataspace', 'UnifiedIndividual__dlm'\r\n\u00a0 \u00a0 );<\/pre>\n<p>&nbsp;<\/p>\n<h2><span class=\"ez-toc-section\" id=\"API-Updates\"><\/span><span style=\"font-weight: 400;\">API Updates<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<h3><span class=\"ez-toc-section\" id=\"1-Named-Query-API-Generally-Available\"><\/span><span style=\"font-weight: 400;\">1. Named Query API: Generally Available<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Define and expose custom SOQL queries as versioned, reusable REST endpoints. Named Query APIs are faster and more efficient than equivalent Flow or Apex processes. Once defined, they are callable as standard REST resources.<\/span><\/p>\n<pre class=\"theme:github font-size:14 nums:false lang:default decode:true \"># Endpoint auto-generated from a Named Query API named \"RecentOpenCases\"\r\nGET \/services\/data\/v66.0\/query\/named\/RecentOpenCases?flow__accountId=001Ws000001234\r\n\u00a0\r\n# Response\r\n{\r\n\u00a0 \"totalSize\": 3,\r\n\u00a0 \"done\": true,\r\n\u00a0 \"records\": [\r\n\u00a0 \u00a0 { \"Id\": \"5001234\", \"CaseNumber\": \"00001001\", \"Status\": \"Open\" },\r\n\u00a0 \u00a0 { \"Id\": \"5001235\", \"CaseNumber\": \"00001002\", \"Status\": \"Open\" },\r\n\u00a0 \u00a0 { \"Id\": \"5001236\", \"CaseNumber\": \"00001003\", \"Status\": \"Open\" }\r\n\u00a0 ]\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"2-Session-IDs-in-Outbound-Messages-Removed\"><\/span><span style=\"font-weight: 400;\">2. Session IDs in Outbound Messages: Removed<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Session IDs can no longer be sent in outbound messages as of February 16, 2026. Audit Setup &gt; Integrations &gt; Outbound Messages. Update all outbound message subscribers to authenticate using OAuth instead of reading a session ID from the message payload.<\/span><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Security-Three-Mandatory-Changes\"><\/span><span style=\"font-weight: 400;\">Security: Three Mandatory Changes<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Spring &#8217;26 brings three mandatory security changes. These are not optional improvements. Every Salesforce development team needs to review and act on each one.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"1-External-Client-Apps-Replace-Connected-Apps\"><\/span><span style=\"font-weight: 400;\">1. External Client Apps Replace Connected Apps<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Creating new Connected Apps is disabled by default for all orgs. Existing Connected Apps continue to work normally, and nothing breaks immediately. But all new integrations must now use External Client Apps (ECA).<\/span><\/p>\n\n<table id=\"tablepress-199\" class=\"tablepress tablepress-id-199\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\">Dimension<\/th><th class=\"column-2\">Connected Apps (Legacy)<\/th><th class=\"column-3\">External Client Apps (New)<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\">Create new<\/td><td class=\"column-2\">Disabled by default<\/td><td class=\"column-3\">Fully supported<\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\">Existing apps<\/td><td class=\"column-2\">Continue working<\/td><td class=\"column-3\">Migration target, plan your timeline<\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\">2GP packaging<\/td><td class=\"column-2\">Limited support<\/td><td class=\"column-3\">Full support<\/td>\n<\/tr>\n<tr class=\"row-5\">\n\t<td class=\"column-1\">Migration path<\/td><td class=\"column-2\">App Manager > Migrate to ECA<\/td><td class=\"column-3\">Original becomes read-only post-migration<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-199 from cache -->\n<p>&nbsp;<\/p>\n<h3><span class=\"ez-toc-section\" id=\"2-Triple-DES-SAML-Retirement\"><\/span><span style=\"font-weight: 400;\">2. Triple DES SAML Retirement<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">SAML SSO using Triple DES will stop functioning entirely in Summer &#8217;26. Find affected configs at Setup &gt; Identity &gt; Single Sign-On Settings, look for &#8216;Triple DES&#8217; in the algorithm column. Migrate to AES-128 or AES-256 now. User lockouts at the deadline require emergency Salesforce Support.<\/span><\/p>\n<h3><span class=\"ez-toc-section\" id=\"3-Session-ID-in-Outbound-Messages-Already-Removed\"><\/span><span style=\"font-weight: 400;\">3. Session ID in Outbound Messages: Already Removed<\/span><span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><span style=\"font-weight: 400;\">If you have any outbound messages still attempting to send session IDs, they are already failing. Audit and update the OAuth authentication immediately. See Section 8.2 for details.<\/span><\/p>\n<h2><span class=\"ez-toc-section\" id=\"Quick-Reference-All-Spring-26-Features\"><\/span><span style=\"font-weight: 400;\">Quick Reference, All Spring &#8217;26 Features<\/span><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n<table id=\"tablepress-200\" class=\"tablepress tablepress-id-200\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\">Feature<\/th><th class=\"column-2\">Area<\/th><th class=\"column-3\">Status<\/th><th class=\"column-4\">Action Required<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\">lwc:on, dynamic event listeners<\/td><td class=\"column-2\">LWC<\/td><td class=\"column-3\">GA \u00b7 API v66<\/td><td class=\"column-4\">Available now, use freely<\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\">GraphQL executeMutation<\/td><td class=\"column-2\">LWC<\/td><td class=\"column-3\">GA \u00b7 API v66<\/td><td class=\"column-4\">Upgrade to API v66 in sf-project.json<\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\">@salesforce\/lightning-types TypeScript<\/td><td class=\"column-2\">LWC<\/td><td class=\"column-3\">Dev Beta<\/td><td class=\"column-4\">npm install --save-dev @salesforce\/lightning-types<\/td>\n<\/tr>\n<tr class=\"row-5\">\n\t<td class=\"column-1\">Complex Template Expressions<\/td><td class=\"column-2\">LWC<\/td><td class=\"column-3\">Beta<\/td><td class=\"column-4\">Sandbox first, enable Beta in Setup<\/td>\n<\/tr>\n<tr class=\"row-6\">\n\t<td class=\"column-1\">standard__flow PageReference<\/td><td class=\"column-2\">LWC<\/td><td class=\"column-3\">GA<\/td><td class=\"column-4\">Available now<\/td>\n<\/tr>\n<tr class=\"row-7\">\n\t<td class=\"column-1\">Error Console<\/td><td class=\"column-2\">LWC<\/td><td class=\"column-3\">GA<\/td><td class=\"column-4\">Setup > User Interface > Advanced Settings<\/td>\n<\/tr>\n<tr class=\"row-8\">\n\t<td class=\"column-1\">Apex Cursors + PaginationCursor<\/td><td class=\"column-2\">Apex<\/td><td class=\"column-3\">GA \u00b7 API v66<\/td><td class=\"column-4\">Available now, no config needed<\/td>\n<\/tr>\n<tr class=\"row-9\">\n\t<td class=\"column-1\">RunRelevantTests<\/td><td class=\"column-2\">Apex \/ Deploy<\/td><td class=\"column-3\">Beta<\/td><td class=\"column-4\">--test-level RunRelevantTests in CLI<\/td>\n<\/tr>\n<tr class=\"row-10\">\n\t<td class=\"column-1\">Picklist values by record type<\/td><td class=\"column-2\">Apex<\/td><td class=\"column-3\">GA<\/td><td class=\"column-4\">ConnectApi.RecordUi.getPicklistValuesByRecordType()<\/td>\n<\/tr>\n<tr class=\"row-11\">\n\t<td class=\"column-1\">Blob.toPdf() new engine<\/td><td class=\"column-2\">Apex<\/td><td class=\"column-3\">GA (Summer '26 enforced)<\/td><td class=\"column-4\">Test in sandbox, check font rendering<\/td>\n<\/tr>\n<tr class=\"row-12\">\n\t<td class=\"column-1\">Agentforce Builder (Canvas + Script)<\/td><td class=\"column-2\">Agentforce<\/td><td class=\"column-3\">Beta<\/td><td class=\"column-4\">Enable Beta in Setup<\/td>\n<\/tr>\n<tr class=\"row-13\">\n\t<td class=\"column-1\">Agent Script DSL<\/td><td class=\"column-2\">Agentforce<\/td><td class=\"column-3\">Beta<\/td><td class=\"column-4\">Install Agent Script VS Code extension<\/td>\n<\/tr>\n<tr class=\"row-14\">\n\t<td class=\"column-1\">Agent Grid<\/td><td class=\"column-2\">Agentforce<\/td><td class=\"column-3\">Beta<\/td><td class=\"column-4\">Available in the Agentforce app<\/td>\n<\/tr>\n<tr class=\"row-15\">\n\t<td class=\"column-1\">Named Query API<\/td><td class=\"column-2\">API<\/td><td class=\"column-3\">GA<\/td><td class=\"column-4\">Setup > Integrations > Named Query API<\/td>\n<\/tr>\n<tr class=\"row-16\">\n\t<td class=\"column-1\">External Client Apps<\/td><td class=\"column-2\">Security<\/td><td class=\"column-3\">MANDATORY<\/td><td class=\"column-4\">Use for all new integrations now<\/td>\n<\/tr>\n<tr class=\"row-17\">\n\t<td class=\"column-1\">Triple DES SAML retirement<\/td><td class=\"column-2\">Security<\/td><td class=\"column-3\">Deadline Summer '26<\/td><td class=\"column-4\">Migrate to AES-128 or AES-256 now<\/td>\n<\/tr>\n<tr class=\"row-18\">\n\t<td class=\"column-1\">Session IDs in outbound messages<\/td><td class=\"column-2\">Security<\/td><td class=\"column-3\">REMOVED Feb 16<\/td><td class=\"column-4\">Switch to OAuth immediately<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-200 from cache -->\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<style>.elementor-16682 .elementor-element.elementor-element-2932a52{text-align:left;}.elementor-16682 .elementor-element.elementor-element-2932a52 > .elementor-widget-container{margin:0px 0px 0px 0px;}.elementor-16682 .elementor-element.elementor-element-0b767d1 .elementor-tab-title{border-width:1px;border-color:#00000014;}.elementor-16682 .elementor-element.elementor-element-0b767d1 .elementor-tab-content{border-width:1px;border-bottom-color:#00000014;}.elementor-16682 .elementor-element.elementor-element-0b767d1 > .elementor-widget-container{margin:0px 0px 0px 0px;}<\/style><div class=\"porto-block elementor elementor-16682\">\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-27707ca elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"27707ca\" data-element_type=\"section\">\r\n\t\t\t\r\n\t\t\t\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\r\n\t\t\t\t\t\t\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-0163611\" data-id=\"0163611\" data-element_type=\"column\">\r\n\r\n\t\t\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\r\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-03a2969 elementor-widget elementor-widget-text-editor\" data-id=\"03a2969\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<style>\/*! elementor - v3.14.0 - 26-06-2023 *\/\n.elementor-widget-text-editor.elementor-drop-cap-view-stacked .elementor-drop-cap{background-color:#69727d;color:#fff}.elementor-widget-text-editor.elementor-drop-cap-view-framed .elementor-drop-cap{color:#69727d;border:3px solid;background-color:transparent}.elementor-widget-text-editor:not(.elementor-drop-cap-view-default) .elementor-drop-cap{margin-top:8px}.elementor-widget-text-editor:not(.elementor-drop-cap-view-default) .elementor-drop-cap-letter{width:1em;height:1em}.elementor-widget-text-editor .elementor-drop-cap{float:left;text-align:center;line-height:1;font-size:50px}.elementor-widget-text-editor .elementor-drop-cap-letter{display:inline-block}<\/style>\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2932a52 elementor-widget elementor-widget-heading\" data-id=\"2932a52\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<style>\/*! elementor - v3.14.0 - 26-06-2023 *\/\n.elementor-heading-title{padding:0;margin:0;line-height:1}.elementor-widget-heading .elementor-heading-title[class*=elementor-size-]>a{color:inherit;font-size:inherit;line-height:inherit}.elementor-widget-heading .elementor-heading-title.elementor-size-small{font-size:15px}.elementor-widget-heading .elementor-heading-title.elementor-size-medium{font-size:19px}.elementor-widget-heading .elementor-heading-title.elementor-size-large{font-size:29px}.elementor-widget-heading .elementor-heading-title.elementor-size-xl{font-size:39px}.elementor-widget-heading .elementor-heading-title.elementor-size-xxl{font-size:59px}<\/style><h1 class=\"elementor-heading-title elementor-size-large\"><span class=\"ez-toc-section\" id=\"FAQs\"><\/span>FAQs <span class=\"ez-toc-section-end\"><\/span><\/h1>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0b767d1 elementor-widget elementor-widget-toggle\" data-id=\"0b767d1\" data-element_type=\"widget\" data-widget_type=\"toggle.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<style>\/*! elementor - v3.14.0 - 26-06-2023 *\/\n.elementor-toggle{text-align:left}.elementor-toggle .elementor-tab-title{font-weight:700;line-height:1;margin:0;padding:15px;border-bottom:1px solid #d5d8dc;cursor:pointer;outline:none}.elementor-toggle .elementor-tab-title .elementor-toggle-icon{display:inline-block;width:1em}.elementor-toggle .elementor-tab-title .elementor-toggle-icon svg{-webkit-margin-start:-5px;margin-inline-start:-5px;width:1em;height:1em}.elementor-toggle .elementor-tab-title .elementor-toggle-icon.elementor-toggle-icon-right{float:right;text-align:right}.elementor-toggle .elementor-tab-title .elementor-toggle-icon.elementor-toggle-icon-left{float:left;text-align:left}.elementor-toggle .elementor-tab-title .elementor-toggle-icon .elementor-toggle-icon-closed{display:block}.elementor-toggle .elementor-tab-title .elementor-toggle-icon .elementor-toggle-icon-opened{display:none}.elementor-toggle .elementor-tab-title.elementor-active{border-bottom:none}.elementor-toggle .elementor-tab-title.elementor-active .elementor-toggle-icon-closed{display:none}.elementor-toggle .elementor-tab-title.elementor-active .elementor-toggle-icon-opened{display:block}.elementor-toggle .elementor-tab-content{padding:15px;border-bottom:1px solid #d5d8dc;display:none}@media (max-width:767px){.elementor-toggle .elementor-tab-title{padding:12px}.elementor-toggle .elementor-tab-content{padding:12px 10px}}.e-con-inner>.elementor-widget-toggle,.e-con>.elementor-widget-toggle{width:var(--container-widget-width);--flex-grow:var(--container-widget-flex-grow)}<\/style>\t\t<div class=\"elementor-toggle\">\n\t\t\t\t\t\t\t<div class=\"elementor-toggle-item\">\n\t\t\t\t\t<h3 id=\"elementor-tab-title-1201\" class=\"elementor-tab-title\" data-tab=\"1\" role=\"button\" aria-controls=\"elementor-tab-content-1201\" aria-expanded=\"false\"><span class=\"ez-toc-section\" id=\"When-did-Spring-26-go-live-in-production\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon elementor-toggle-icon-left\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-closed\"><i class=\"fas fa-caret-right\"><\/i><\/span>\n\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-opened\"><i class=\"elementor-toggle-icon-opened fas fa-caret-up\"><\/i><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-toggle-title\" tabindex=\"0\">When did Spring '26 go live in production?<\/a>\n\t\t\t\t\t<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\t\t\t\t\t<div id=\"elementor-tab-content-1201\" class=\"elementor-tab-content elementor-clearfix\" data-tab=\"1\" role=\"region\" aria-labelledby=\"elementor-tab-title-1201\"><p><span style=\"font-weight: 400;\">Three waves: January 16, February 13, and February 20, 2026. Sandbox preview began January 9\u201310. A pre-release Developer Edition has been available since December 18, 2025. Check status.salesforce.com for your specific instance date.<\/span><\/p><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-toggle-item\">\n\t\t\t\t\t<h3 id=\"elementor-tab-title-1202\" class=\"elementor-tab-title\" data-tab=\"2\" role=\"button\" aria-controls=\"elementor-tab-content-1202\" aria-expanded=\"false\"><span class=\"ez-toc-section\" id=\"What-API-version-does-Spring-26-introduce\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon elementor-toggle-icon-left\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-closed\"><i class=\"fas fa-caret-right\"><\/i><\/span>\n\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-opened\"><i class=\"elementor-toggle-icon-opened fas fa-caret-up\"><\/i><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-toggle-title\" tabindex=\"0\">What API version does Spring '26 introduce?<\/a>\n\t\t\t\t\t<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\t\t\t\t\t<div id=\"elementor-tab-content-1202\" class=\"elementor-tab-content elementor-clearfix\" data-tab=\"2\" role=\"region\" aria-labelledby=\"elementor-tab-title-1202\"><p><span style=\"font-weight: 400;\">API version 66.0. Features requiring v66+: Apex Cursors (GA), GraphQL executeMutation, the lwc:on directive, and RunRelevantTests. Update sf-project.json to &#8220;sourceApiVersion&#8221;: &#8220;66.0&#8221; and verify your integrations are compatible.<\/span><\/p><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-toggle-item\">\n\t\t\t\t\t<h3 id=\"elementor-tab-title-1203\" class=\"elementor-tab-title\" data-tab=\"3\" role=\"button\" aria-controls=\"elementor-tab-content-1203\" aria-expanded=\"false\"><span class=\"ez-toc-section\" id=\"What-is-the-difference-between-Apex-Cursor-and-PaginationCursor\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon elementor-toggle-icon-left\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-closed\"><i class=\"fas fa-caret-right\"><\/i><\/span>\n\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-opened\"><i class=\"elementor-toggle-icon-opened fas fa-caret-up\"><\/i><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-toggle-title\" tabindex=\"0\">What is the difference between Apex Cursor and PaginationCursor?<\/a>\n\t\t\t\t\t<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\t\t\t\t\t<div id=\"elementor-tab-content-1203\" class=\"elementor-tab-content elementor-clearfix\" data-tab=\"3\" role=\"region\" aria-labelledby=\"elementor-tab-title-1203\"><p><span style=\"font-weight: 400;\">Database.Cursor is for background async processing, up to 50M records, 10K instances\/day, ideal for Queueable chaining. Database.PaginationCursor is for user-facing pagination, up to 100K records, 200K instances\/day, consistent page sizes, designed for LWC @AuraEnabled integration.<\/span><\/p><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-toggle-item\">\n\t\t\t\t\t<h3 id=\"elementor-tab-title-1204\" class=\"elementor-tab-title\" data-tab=\"4\" role=\"button\" aria-controls=\"elementor-tab-content-1204\" aria-expanded=\"false\"><span class=\"ez-toc-section\" id=\"Do-existing-Connected-Apps-need-to-be-migrated-now\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon elementor-toggle-icon-left\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-closed\"><i class=\"fas fa-caret-right\"><\/i><\/span>\n\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-opened\"><i class=\"elementor-toggle-icon-opened fas fa-caret-up\"><\/i><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-toggle-title\" tabindex=\"0\">Do existing Connected Apps need to be migrated now?<\/a>\n\t\t\t\t\t<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\t\t\t\t\t<div id=\"elementor-tab-content-1204\" class=\"elementor-tab-content elementor-clearfix\" data-tab=\"4\" role=\"region\" aria-labelledby=\"elementor-tab-title-1204\"><p><span style=\"font-weight: 400;\">No, existing Connected Apps continue working normally. What changes is that you can no longer create new ones without contacting Salesforce Support. Plan migration in your own timeline. Migration: App Manager &gt; your Connected App &gt; dropdown &gt; &#8216;Migrate to External Client App&#8217;.<\/span><\/p><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-toggle-item\">\n\t\t\t\t\t<h3 id=\"elementor-tab-title-1205\" class=\"elementor-tab-title\" data-tab=\"5\" role=\"button\" aria-controls=\"elementor-tab-content-1205\" aria-expanded=\"false\"><span class=\"ez-toc-section\" id=\"What-is-Agent-Script\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon elementor-toggle-icon-left\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-closed\"><i class=\"fas fa-caret-right\"><\/i><\/span>\n\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-opened\"><i class=\"elementor-toggle-icon-opened fas fa-caret-up\"><\/i><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-toggle-title\" tabindex=\"0\">What is Agent Script?<\/a>\n\t\t\t\t\t<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\t\t\t\t\t<div id=\"elementor-tab-content-1205\" class=\"elementor-tab-content elementor-clearfix\" data-tab=\"5\" role=\"region\" aria-labelledby=\"elementor-tab-title-1205\"><p><span style=\"font-weight: 400;\">A new DSL (Beta) that combines natural language instructions with deterministic constructs like if-else and variable bindings. Unlike freeform system prompts, Agent Script is version-controllable, diffable, and produces more predictable agent behavior.<\/span><\/p><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-toggle-item\">\n\t\t\t\t\t<h3 id=\"elementor-tab-title-1206\" class=\"elementor-tab-title\" data-tab=\"6\" role=\"button\" aria-controls=\"elementor-tab-content-1206\" aria-expanded=\"false\"><span class=\"ez-toc-section\" id=\"What-is-the-Triple-DES-deadline\"><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon elementor-toggle-icon-left\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-closed\"><i class=\"fas fa-caret-right\"><\/i><\/span>\n\t\t\t\t\t\t\t\t<span class=\"elementor-toggle-icon-opened\"><i class=\"elementor-toggle-icon-opened fas fa-caret-up\"><\/i><\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t\t\t\t\t<a class=\"elementor-toggle-title\" tabindex=\"0\">What is the Triple DES deadline?<\/a>\n\t\t\t\t\t<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\t\t\t\t\t<div id=\"elementor-tab-content-1206\" class=\"elementor-tab-content elementor-clearfix\" data-tab=\"6\" role=\"region\" aria-labelledby=\"elementor-tab-title-1206\"><p><span style=\"font-weight: 400;\">Summer &#8217;26. Any SAML SSO config using Triple DES stops working entirely at that point. Lockouts at the deadline require emergency Salesforce Support. Migrate to AES-128 or AES-256 now, check Setup &gt; Identity &gt; Single Sign-On Settings.<\/span><\/p><\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t\t\t\t\t<script type=\"application\/ld+json\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@type\":\"FAQPage\",\"mainEntity\":[{\"@type\":\"Question\",\"name\":\"When did Spring '26 go live in production?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"<p><span style=\\\"font-weight: 400;\\\">Three waves: January 16, February 13, and February 20, 2026. Sandbox preview began January 9\\u201310. A pre-release Developer Edition has been available since December 18, 2025. Check status.salesforce.com for your specific instance date.<\\\/span><\\\/p>\"}},{\"@type\":\"Question\",\"name\":\"What API version does Spring '26 introduce?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"<p><span style=\\\"font-weight: 400;\\\">API version 66.0. Features requiring v66+: Apex Cursors (GA), GraphQL executeMutation, the lwc:on directive, and RunRelevantTests. Update sf-project.json to &#8220;sourceApiVersion&#8221;: &#8220;66.0&#8221; and verify your integrations are compatible.<\\\/span><\\\/p>\"}},{\"@type\":\"Question\",\"name\":\"What is the difference between Apex Cursor and PaginationCursor?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"<p><span style=\\\"font-weight: 400;\\\">Database.Cursor is for background async processing, up to 50M records, 10K instances\\\/day, ideal for Queueable chaining. Database.PaginationCursor is for user-facing pagination, up to 100K records, 200K instances\\\/day, consistent page sizes, designed for LWC @AuraEnabled integration.<\\\/span><\\\/p>\"}},{\"@type\":\"Question\",\"name\":\"Do existing Connected Apps need to be migrated now?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"<p><span style=\\\"font-weight: 400;\\\">No, existing Connected Apps continue working normally. What changes is that you can no longer create new ones without contacting Salesforce Support. Plan migration in your own timeline. Migration: App Manager &gt; your Connected App &gt; dropdown &gt; &#8216;Migrate to External Client App&#8217;.<\\\/span><\\\/p>\"}},{\"@type\":\"Question\",\"name\":\"What is Agent Script?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"<p><span style=\\\"font-weight: 400;\\\">A new DSL (Beta) that combines natural language instructions with deterministic constructs like if-else and variable bindings. Unlike freeform system prompts, Agent Script is version-controllable, diffable, and produces more predictable agent behavior.<\\\/span><\\\/p>\"}},{\"@type\":\"Question\",\"name\":\"What is the Triple DES deadline?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"<p><span style=\\\"font-weight: 400;\\\">Summer &#8217;26. Any SAML SSO config using Triple DES stops working entirely at that point. Lockouts at the deadline require emergency Salesforce Support. Migrate to AES-128 or AES-256 now, check Setup &gt; Identity &gt; Single Sign-On Settings.<\\\/span><\\\/p>\"}}]}<\/script>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\r\n\t\t\t\t<\/div>\r\n\t\t\t\t\t\t<\/div>\r\n\t\t\t\t<\/section>\r\n\t\t<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Quick Overview: This guide covers all major Salesforce Spring &#8217;26 developer updates, from LWC template expressions and Apex Cursors to Agentforce Builder, mandatory security migrations, Flow logging, GraphQL mutations, and more. &nbsp; Complex Template Expressions in LWC (Beta), write JS inline in templates Apex Cursors are now Generally Available, process up to 50M records Agentforce [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":16699,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_yoast_wpseo_meta-robots-noindex":"","_yoast_wpseo_meta-robots-nofollow":"","_yoast_wpseo_canonical":"","_yoast_wpseo_opengraph-title":"Salesforce Spring '26 Release: The Developer's Guide","_yoast_wpseo_opengraph-description":"Everything developers need from the Salesforce Spring '26 release: LWC updates, Apex Cursors, Agentforce Builder, security migrations, and Flow enhancements.","_yoast_wpseo_opengraph-image":"","_yoast_wpseo_twitter-title":"Salesforce Spring '26 Release: Developer's Guide","_yoast_wpseo_twitter-description":"LWC updates, Apex Cursors, Agentforce Builder, security migrations, and Flow enhancements , the Salesforce Spring '26 features developers should act on.","_yoast_wpseo_twitter-image":"","_wp_applaud_exclude":false,"footnotes":""},"categories":[85],"tags":[2433,1874,2432,2434],"class_list":["post-16680","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-salesforce","tag-agentforce","tag-salesforce-agentforce","tag-salesforce-spring-26","tag-salesforce-spring-26-update"],"featured_image_src":{"landsacpe":["https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image6-1000x445.png",1000,445,true],"list":["https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image6-463x348.png",463,348,true],"medium":["https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image6-300x169.png",300,169,true],"full":["https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image6.png",1000,563,false]},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>The Salesforce Developer&#039;s Guide to the Spring &#039;26 Release<\/title>\n<meta name=\"description\" content=\"Salesforce Spring &#039;26 release guide for developers: LWC updates, Apex Cursors, Agentforce Builder, security migrations, and Flow enhancements.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Salesforce Spring &#039;26 Release: The Developer&#039;s Guide\" \/>\n<meta property=\"og:description\" content=\"Everything developers need from the Salesforce Spring &#039;26 release: LWC updates, Apex Cursors, Agentforce Builder, security migrations, and Flow enhancements.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/\" \/>\n<meta property=\"og:site_name\" content=\"Learn About Digital Transformation &amp; Development | DianApps Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-06-15T09:38:52+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-16T05:42:32+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image6.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"563\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Vikash Soni\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:title\" content=\"Salesforce Spring &#039;26 Release: Developer&#039;s Guide\" \/>\n<meta name=\"twitter:description\" content=\"LWC updates, Apex Cursors, Agentforce Builder, security migrations, and Flow enhancements , the Salesforce Spring &#039;26 features developers should act on.\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Vikash Soni\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"22 minutes\" \/>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"The Salesforce Developer's Guide to the Spring '26 Release","description":"Salesforce Spring '26 release guide for developers: LWC updates, Apex Cursors, Agentforce Builder, security migrations, and Flow enhancements.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/","og_locale":"en_US","og_type":"article","og_title":"Salesforce Spring '26 Release: The Developer's Guide","og_description":"Everything developers need from the Salesforce Spring '26 release: LWC updates, Apex Cursors, Agentforce Builder, security migrations, and Flow enhancements.","og_url":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/","og_site_name":"Learn About Digital Transformation &amp; Development | DianApps Blog","article_published_time":"2026-06-15T09:38:52+00:00","article_modified_time":"2026-06-16T05:42:32+00:00","og_image":[{"width":1000,"height":563,"url":"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image6.png","type":"image\/png"}],"author":"Vikash Soni","twitter_card":"summary_large_image","twitter_title":"Salesforce Spring '26 Release: Developer's Guide","twitter_description":"LWC updates, Apex Cursors, Agentforce Builder, security migrations, and Flow enhancements , the Salesforce Spring '26 features developers should act on.","twitter_misc":{"Written by":"Vikash Soni","Est. reading time":"22 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/#article","isPartOf":{"@id":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/"},"author":{"name":"Vikash Soni","@id":"https:\/\/dianapps.com\/blog\/#\/schema\/person\/0126fafc83e42bece2acbfe92f7d0f4f"},"headline":"The Salesforce Developer&#8217;s Guide to the Spring &#8217;26 Release","datePublished":"2026-06-15T09:38:52+00:00","dateModified":"2026-06-16T05:42:32+00:00","mainEntityOfPage":{"@id":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/"},"wordCount":2489,"commentCount":0,"image":{"@id":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/#primaryimage"},"thumbnailUrl":"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image6.png","keywords":["agentforce","Salesforce Agentforce","Salesforce spring 26","salesforce spring 26 update"],"articleSection":["Salesforce"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/","url":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/","name":"The Salesforce Developer's Guide to the Spring '26 Release","isPartOf":{"@id":"https:\/\/dianapps.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/#primaryimage"},"image":{"@id":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/#primaryimage"},"thumbnailUrl":"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image6.png","datePublished":"2026-06-15T09:38:52+00:00","dateModified":"2026-06-16T05:42:32+00:00","author":{"@id":"https:\/\/dianapps.com\/blog\/#\/schema\/person\/0126fafc83e42bece2acbfe92f7d0f4f"},"description":"Salesforce Spring '26 release guide for developers: LWC updates, Apex Cursors, Agentforce Builder, security migrations, and Flow enhancements.","breadcrumb":{"@id":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/#primaryimage","url":"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image6.png","contentUrl":"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2026\/06\/image6.png","width":1000,"height":563,"caption":"The Salesforce Developer's Guide to the Spring '26 Release"},{"@type":"BreadcrumbList","@id":"https:\/\/dianapps.com\/blog\/salesforce-spring-26-release-developers-guide\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/dianapps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"The Salesforce Developer&#8217;s Guide to the Spring &#8217;26 Release"}]},{"@type":"WebSite","@id":"https:\/\/dianapps.com\/blog\/#website","url":"https:\/\/dianapps.com\/blog\/","name":"Learn About Digital Transformation &amp; Development | DianApps Blog","description":"Dianapps","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/dianapps.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/dianapps.com\/blog\/#\/schema\/person\/0126fafc83e42bece2acbfe92f7d0f4f","name":"Vikash Soni","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2022\/07\/cropped-vikash-96x96.png","url":"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2022\/07\/cropped-vikash-96x96.png","contentUrl":"https:\/\/dianapps.com\/blog\/wp-content\/uploads\/2022\/07\/cropped-vikash-96x96.png","caption":"Vikash Soni"},"description":"Vikash Soni, the visionary CEO and Co-founder of DianApps. With his profound expertise in Android and iOS app development, he leads the team to deliver top-notch solutions to clients worldwide. Under his guidance, the company has achieved remarkable success, earning a reputation as a leading web and mobile app development company.","sameAs":["https:\/\/www.linkedin.com\/in\/vikash-soni-59726530\/"],"url":"https:\/\/dianapps.com\/blog\/author\/infodianapps-com\/"}]}},"_links":{"self":[{"href":"https:\/\/dianapps.com\/blog\/wp-json\/wp\/v2\/posts\/16680","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dianapps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dianapps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dianapps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dianapps.com\/blog\/wp-json\/wp\/v2\/comments?post=16680"}],"version-history":[{"count":8,"href":"https:\/\/dianapps.com\/blog\/wp-json\/wp\/v2\/posts\/16680\/revisions"}],"predecessor-version":[{"id":16707,"href":"https:\/\/dianapps.com\/blog\/wp-json\/wp\/v2\/posts\/16680\/revisions\/16707"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dianapps.com\/blog\/wp-json\/wp\/v2\/media\/16699"}],"wp:attachment":[{"href":"https:\/\/dianapps.com\/blog\/wp-json\/wp\/v2\/media?parent=16680"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dianapps.com\/blog\/wp-json\/wp\/v2\/categories?post=16680"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dianapps.com\/blog\/wp-json\/wp\/v2\/tags?post=16680"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}