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.

Important

Install the Package 

To install LWS CLI, open a terminal on your development environment and perform these steps.

  1. Install the node project dependencies.

    1npm install
  2. Install LWS CLI and the LWS configuration package from this package location.

    1# Globally — `lws` is available everywhere
    2npm install -g @locker/cli
    3# or:
    4yarn global add @locker/cli
  3. Run this command to install at least one Playwright browser binary.

    1# Default: just chromium
    2  npx playwright install chromium
    3
    4  # Or all three engines (chromium, firefox, webkit)
    5  npx playwright install
  4. Verify if LWS CLI is installed.

    1lws --version

Key Features 

Here are the key features and commands of LWS CLI.

1. Fast Code Evaluation 

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.

1lws eval "console.log('hello from inside the sandbox')"

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.

    1lws eval "document.body.remove()"`

    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 --before and --after flags 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 on window). This prevents untrusted sandboxed code from reading this data back.

    1lws eval --before "document.cookie = '_auth_token=SECRET-host-only'" \
    2       --after "console.log('[host] real cookie jar:', document.cookie)" \
    3       "document.cookie = 'session=abc'; console.log('[sandbox] reads:', document.cookie)"

    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 a onerror event 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.

    1lws eval --after "console.log('[host] sanitized DOM:', document.querySelector('div#sink').outerHTML)" \
    2        "const d = document.createElement('div'); d.id = 'sink'; document.body.appendChild(d);
    3        d.innerHTML = '<script>alert(1)</script><img src=data:, onerror=alert(2)><b>kept</b>';"

    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>
     

2. Local LWC Rendering 

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, and parent rendered sequence
  • Outputs the full compiled LWC code directly to the terminal for fast debugging
1lws component ./test/fixtures/c/helloWorld

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.

3. Persistent State 

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.

1lws repl
> 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.

1lws repl --before "/* pre-setup system code */" --after "/* post-teardown system code */"

Release Preview

This release is in preview. Features described here don't become generally available until the latest general availability date that Salesforce announces for this release. Before then, and where features are noted as beta, pilot, or developer preview, we can't guarantee general availability within any particular time frame or at all. Make your purchase decisions only on the basis of generally available products and features.