Platform
Lightning Web Security vs Lightning Locker: what breaks when you switch
Lightning Web Security gives you back most of normal JavaScript, but it changes how shared globals and browser storage behave, and it tends to fail without throwing an error. Here is the mechanism difference, the failures that stay silent, and how to turn it on in a sandbox without a Monday incident.
A chart renders in your sandbox and fails in production, with nothing in the console to explain it. The component didn’t change. The org’s security layer did.
Salesforce runs every Lightning component inside one of two security architectures: the older Lightning Locker, or the newer Lightning Web Security. New orgs have shipped with LWS on by default since Winter ‘23, and it reached GA for both Lightning web components and Aura in Summer ‘23. Older orgs still default to Locker.
At some point you flip the switch. The thing to know first: LWS changes how shared globals and browser storage behave, and much of what it changes fails without throwing. Turn it on in a sandbox and test every third-party dependency before you trust it in production.
I’ll walk through what each layer does, the failures that stay quiet, the libraries that stop working, and a turn-on sequence that surfaces the breakage before your users do.
Two different ways to cage a component
Lightning Locker and LWS solve the same problem, keeping one namespace’s JavaScript from touching another’s, in opposite ways.
Locker wraps things. It intercepts access to window, document, and DOM elements and hands your code secure stand-ins: SecureWindow, SecureDocument, SecureElement, and the generic SecureObject.
It filters what a component sees with the JavaScript Proxy object, so a component only reaches DOM created inside its own namespace, and each wrapper exposes a curated allowlist of APIs. Reach for a property outside that list across a namespace boundary and you get undefined back. The cost of all that wrapping is that legitimate code breaks whenever a library expects the real window and finds a proxy instead.
LWS stops wrapping and starts sandboxing. Each namespace gets its own JavaScript sandbox, a small virtual environment with its own slice of globals, storage, and network, and inside it your code sees the real window, document, and element objects.
Isolation comes from a technique Salesforce calls a distortion: a distortion rewrites a specific native API so it can’t reach data outside the sandbox. APIs that aren’t distorted keep their native behavior. Your code runs in strict mode, and a component’s shadowRoot has to be closed.
Dropping the wrappers has two effects. Far more standard JavaScript and third-party code runs unmodified, and it runs faster because there is no wrapper indirection on every call. The catch is that isolation shifted from blocking and wrapping to rewriting APIs in place, and a rewrite that returns a different value is harder to catch than a wrapper that throws.
What LWS gives back
The reason to move is that LWS removes most of the restrictions that made Locker painful.
- Cross-namespace imports work. A component can import and compose or extend a component from another namespace, which Locker blocked outright.
- Custom elements and third-party web components work. Locker blocked both.
- More third-party libraries work, because they get the real global objects instead of a secure wrapper that hides half their surface.
iframecontent is reachable when the frame’ssrcis unset orabout:blank. Setsrcto any URL and LWS treats the frame as cross-origin, same-origin or not, so plan for that.
For a team that spent the Locker years rewriting vendor libraries or giving up on them, this is the payoff. If your LWC work leans on charting, grids, or date pickers from npm, more of them will load on the first try.
The failures that don’t throw
Here is where migrations go wrong. LWS does not announce most of its changes.
Globals don’t cross namespaces. A distortion only lets a component change the virtual window inside its own namespace sandbox. If your code reads a global that a component in another namespace set, LWS hands back undefined, and nothing errors.
A value you relied on is simply missing, and the symptom surfaces three functions later as a null you can’t trace. The documented fix is to stop passing state through globals and pass it as function or constructor arguments.
Local storage breaks across the switch. LWS generates namespace-unique key names for localStorage and sessionStorage, so data written while Locker was on is unreadable once LWS is on, and the reverse.
Flip the setting and a returning user’s cached preference, draft, or token vanishes without an exception. If you store anything in the browser, rewrite it after you change the setting, and expect the first load to behave like a brand-new visitor.
Distortions can return the wrong answer. A June 2026 Salesforce Developers post on LWC anti-patterns puts it bluntly: distorted APIs can return incorrect data in production with no error or warning, and the set of distorted APIs changes between releases.
So you cannot reason about LWS behavior from memory. The LWS Distortion Viewer in the Component Library is the current source of truth for which APIs are modified, and it is worth checking against every library that touches the DOM or the global scope. The class of bug that erodes trust is the component that renders and returns a subtly wrong value, because that one ships.
The libraries that stop working
Some breakage is specific enough to name, and all of it is documented by Salesforce rather than guessed at.
- Whole-page analytics such as Google Analytics and Adobe Analytics are blocked. They need unrestricted access to the entire page, which is the exact thing a sandbox prevents. The only documented escape is an Experience Cloud site where an admin can edit the head markup.
- Libraries that attach to
window, or expectthisandglobalto be defined, need adjustment, because inside a sandbox both areundefined. The standard workaround is to assignselfto aglobalvariable inside the library’s closure. - Objects passed between components arrive proxied, so serializing a value to a JSON string and parsing it on the other side avoids a class of proxy problems.
- Scripts that set
"use strict"explicitly interfere with LWS, and the fix is to remove that line from the third-party script. - The Lightning Out 2.0 library can’t be loaded from an LWC at all, because LWS blocks inserting a
<script>element.
LWS also fences off a couple of globals you might assume are free. window.top and window.location aren’t accessible by default, and shadowing those names can throw an initialization error that reads like a typo.
Aura and Experience Cloud carry their own rules
The single org setting covers both LWC and Aura, but Aura is where I’d test hardest. Salesforce documents that async/await and dynamic import can throw runtime errors in Aura under LWS, and that some Aura errors aren’t surfaced while LWS is on, which makes them slow to find.
Components from some ISVs and older frameworks that lean on Aura stopped loading when new orgs started defaulting to LWS, and the fix usually came from the vendor rather than a config change on your side.
Experience Cloud hides a trap worth calling out. LWR sites use LWS, but the org-level Session Settings toggle has no effect on them. A separate site-level setting in Experience Builder controls LWS for an LWR site, independent of the org setting.
Flip the org switch, test your internal apps, and your LWR site is still running on whatever the site-level setting says. LWR sites also carry extra limits under LWS: no await/async expressions, and no access to document.domain, document.location, window.location, or window.top.
Turning it on without a Monday incident
The setting lives in Setup under Session Settings, labeled “Use Lightning Web Security for Lightning web components and Aura components.” The setting is org-wide. You can’t enable it per component, it isn’t tied to an API version the way Locker is, and after you change it you have to clear the browser cache so the right files load. Keep Stricter Content Security Policy enabled too, because LWS depends on it.
A sequence that works:
- Fix the LWS ESLint errors in your codebase first. Salesforce ships rules that flag the patterns LWS will reject, and clearing them is free signal before you touch an org setting.
- Enable it in a sandbox, never production first, and run full functional testing there. The sandbox is where the silent failures become visible.
- Use the LWS Console for quick checks while you code, but know its ceiling. It evaluates pure JavaScript only, and skips modules with
import/exportand decorators like@apiand@wire, so passing the console is not passing the org. - Re-test under Locker too. If you changed code to satisfy LWS, turn the setting back off in the sandbox and confirm the same components still work on Locker, because some orgs and installs you support may still run it.
If you publish managed packages, this stops being optional. Package authors have to test under both Locker and LWS, since you don’t control which the subscriber runs, and a component that references an LWC from a managed package needs LWS enabled in the subscriber’s org. Building to the security bar the AppExchange checks already means testing across configurations, and this is one more axis of that matrix.
One caution on framing. Salesforce recommends LWS and ships it on for new orgs, and Locker is the legacy layer. There is no published date by which Locker will be forced off or removed, so treat the move as deliberate and soon, not as a race against a deadline that doesn’t exist.
The real cost of this migration isn’t the code you rewrite. It’s that LWS trades Locker’s loud failures for silent ones, so the work is testing, not fixing. Budget a full functional pass in a sandbox, check every DOM-touching dependency against the Distortion Viewer, and rewrite anything in browser storage. Do that and the switch is uneventful, which is what a security change should be.
Understanding the basics
Is Lightning Web Security enabled by default?
For orgs created in Winter ‘23 or later, yes. LWS reached general availability for both Lightning web components and Aura components in Summer ‘23, and new orgs ship with it on. Orgs created before Winter ‘23 still default to Lightning Locker, and you turn LWS on through a single org-wide setting in Session Settings. The setting can’t be scoped to individual components, and it isn’t tied to an API version.
What is the difference between Lightning Locker and Lightning Web Security?
Locker enforces isolation by wrapping window, document, and DOM elements in secure proxies and exposing only an allowlist of APIs, which breaks libraries that expect the real objects. LWS instead gives each namespace its own JavaScript sandbox, exposes the real globals inside it, and isolates namespaces with distortions that rewrite specific native APIs. More standard and third-party JavaScript runs under LWS, and it runs faster, but behavior changes are easier to miss because a distortion can alter results without throwing.
What breaks when you enable Lightning Web Security?
The common ones are silent. Globals set in another namespace read back as undefined, local and session storage written before the switch become unreadable after it, and distorted APIs can return different values with no error. Whole-page analytics libraries like Google Analytics are blocked, libraries that attach to window or use explicit "use strict" need changes, and window.top and window.location are restricted by default. Aura components and Experience Cloud LWR sites have additional limits, so test those paths specifically.
Does the org-level LWS setting control Experience Cloud sites?
No, and this is a frequent surprise. LWR sites in Experience Cloud use LWS, but a separate site-level setting in Experience Builder controls it, independent of the org-wide Session Settings toggle. Changing the org setting does not change an LWR site’s behavior, so you have to set it in both places. LWR sites under LWS also block await/async expressions and access to document.domain, document.location, window.location, and window.top.
Planning an LWS migration, or shipping a managed package that has to pass review and run on both security layers? Talk to us. Getting components that survive the switch without a surprise in production is the kind of engineering we build to.