Local Development with LWS CLI
The Lightning Web Security (LWS) CLI brings the Salesforce LWS runtime directly to your local terminal. Instead of relying on slow deploy-and-test loops, hosted web consoles, or manual copy-pasting, the CLI provides a fast, scriptable, local environment. You can use this environment to test and debug Lightning Web Components (LWC) and JavaScript code.
LWS CLI shrinks the feedback loop rather than replacing end-to-end testing. Real user interactions, live data, cross-org behavior, and auth flows still require full deployments. However, the CLI catches most LWS issues locally in seconds, preventing problems before deployment and reducing org round trips.
To install LWS CLI, open a terminal on your development environment and perform these steps.
-
Install the node project dependencies.
-
Install LWS CLI and the LWS configuration package from this package location.
-
Run this command to install at least one Playwright browser binary.
-
Verify if LWS CLI is installed.
Here are the key features and commands of LWS CLI.
Use lws eval to compile and run your code inside a real, sandboxed browser runtime (Chromium). In this example, LWS compiles the code, opens a real browser, starts the production sandbox, and logs hello from inside the sandbox within seconds.
The lws eval command:
-
Blocks dangerous operations by enforcing real LWS security policies. In this example, when untrusted code attempts to delete the host page, the sandbox blocks the request with a locker-security error and terminates the process with a non-zero exit code.
Expected output:
> (function () {
> 'use strict';
>
> window.evaluateInSandbox('cli', () => {
> document.body.remove();
> });
> })();
>
> [browser:pageerror] Lightning Web Security: Cannot remove BODY.
-
Enforces multitenant data isolation through the LWS realm boundary and API distortions. Use the
--beforeand--afterflags to run system-mode setup and teardown scripts that plant host-page state (such as setting a session token or Cross-Site Request Forgery (CSRF) credential onwindow). This prevents untrusted sandboxed code from reading this data back.Expected output:
> (function () { > 'use strict'; > window.evaluateInSandbox('cli', () => { > document.cookie = 'session=abc'; console.log('[sandbox] reads:', document.cookie); > }); > })(); > [browser:log] [sandbox] reads: session=abc > [browser:log] [host] real cookie jar: auth_token=SECRET-host-only; LSKey-cli$session=abc -
Automatically sanitizes untrusted markup at the boundary before it hits the live Document Object Model (DOM), when the untrusted markup is written into the DOM (for example, assigning to
innerHTML). In this example, the script attempts to inject unsafe elements: a<script>HTML tag and aonerrorevent handler. In such cases, LWS removes the dangerous parts while preserving safe HTML tags, such as<img>and<b>. Instead of returning an error or refusing the input, LWS delivers a safe, sanitized DOM tree without requiring the sandbox to detect the threat.Expected output:
> (function () { > 'use strict'; > window.evaluateInSandbox('cli', () => { > const d = document.createElement('div'); d.id = 'sink'; document.body.appendChild(d); > d.innerHTML = '<script>alert(1)</script><img src=data:, onerror=alert(2)><b>kept</b>'; > }); > })(); > [browser:log][host] sanitized DOM: <div id="sink"><img src="data:,"><b>kept</b></div>
To render local LWC directories instantly by using the production LWC compiler, flags, and sandbox runtime, use the lws component command with a directory path. Using this command is faster than running local code through the web console, which requires deploying to a scratch org and waiting for build cycles.
In this example, the lws component uses a local component directory. A one-second local feedback loop running the production LWC engine and sandbox runtime instantly:
- Streams browser logs
- Verifies lifecycle callbacks in
parent connected,child connected, andparent renderedsequence - Outputs the full compiled LWC code directly to the terminal for fast debugging
Expected output:
> ((lwc) => {
> ...
> /* eslint-disable class-methods-use-this, no-console */
> class HelloWorld extends (...) {
> connectedCallback() {
> console.log('hello-world connected');
> }
> ...
> });
> [browser:log] hello-world connected
> [browser:log] wrapped-box connected
> [browser:log] hello-world rendered
The --headed flag with the lws component command opens a live browser window with Chrome DevTools, which enables complete Shadow DOM inspection, breakpoint debugging, and step-through capabilities without deploying to an org. You can analyze the sources and also view the fully bundled component-compiled code.
The lws repl command preserves state across multiple input lines, so that variables, functions, and array bindings remain persistent in the same sandbox environment. This command offers an interactive JavaScript Read-Eval-Print Loop (REPL) wrapped inside the LWS security membrane.
In this example, lws repl opens an interactive, multiline JavaScript shell wrapped in an LWS sandbox. The state persists across lines of code within the sandbox, preserving array bindings and multiline functions until the session ends with .exit.
> lws repl ready (chromium, key="cli"). Type .help for commands, .exit or Ctrl+D to quit.
lws> 1 + 2
> 3
lws> let arr = [1, 2, 3]
> [ 1, 2, 3 ]
lws> arr
> [ 1, 2, 3 ]
lws> let double = function(n) { ... return n * 2 ... }
> 'function(n) {\n return n * 2\n}'
lws> double(2)
>4
lws> .exit
The lws repl command also supports --before and --after flags to run system-level setup, or to remove scripts before and after entering the REPL.