# lpm run (/docs/dev/run)



```bash
lpm run <scripts...> [-- script-args...]
```

Runs one or more `scripts` entries from `package.json`. With multiple scripts, runs them sequentially by default; pass `-p` to run in parallel.

## Shorthand: `lpm <script-or-bin>` without `run` [#shorthand-lpm-script-or-bin-without-run]

`lpm` falls through to the same task runner as `lpm run <name>` when the first argument isn't a known subcommand. That means plain shorthand script invocations pick up `lpm.json` meta-tasks, `dependsOn` expansion, caching, and the normal script/task resolution rules.

```bash
lpm build              # equivalent to lpm run build
lpm typecheck          # equivalent to lpm run typecheck
lpm verify             # equivalent to lpm run verify (including lpm.json meta-tasks)
lpm jest --watch       # runs node_modules/.bin/jest --watch if no script/task named "jest" exists
```

The lookup only kicks in for unknown subcommand names — built-in commands always win. So `lpm test` runs the Vitest/Jest forwarder (built-in `lpm test`), not your `"test"` script entry. To force the script entry when a built-in conflicts, use `lpm run <name>` explicitly.

If no `package.json` script or `lpm.json` task matches the shorthand name, LPM CLI tries a project-local binary with the same resolver as [`lpm exec`](/docs/dev/exec). That fallback searches only `node_modules/.bin` directories for the project/workspace; it does not run arbitrary system PATH binaries and it does not use a shell. Scripts and tasks still win over same-named local binaries.

Path-like invocations such as `lpm scripts/seed.ts` use the source-file runner instead of the shorthand lookup.

Use `lpm run` when you need runner flags. `lpm build --filter web` forwards `--filter web` to your script; `lpm run build --filter web` applies LPM CLI's workspace selection.

## Hidden package.json scripts [#hidden-packagejson-scripts]

Package scripts whose name starts with `.` are hidden helper scripts:

```json title="package.json"
{
  "scripts": {
    "build": "lpm run .build",
    ".build": "tsc -p tsconfig.build.json"
  }
}
```

`lpm run .build` and the shorthand `lpm .build` are rejected when invoked directly from your shell. Hidden scripts are also omitted from missing-script suggestions and script listings.

Visible scripts may call hidden scripts, and `lpm.json` task dependencies may reference them:

```json title="lpm.json"
{
  "tasks": {
    "build": {
      "dependsOn": [".build"]
    }
  }
}
```

Use this for internal building blocks you do not want to expose as top-level project commands.

## Examples [#examples]

```bash
lpm run build
lpm run lint test                 # sequential
lpm run -p lint test typecheck    # parallel
lpm run dev -- --port 4000        # forward args to the script
lpm run build --filter web        # workspaces: build only the web member
lpm run build --all               # build every workspace member
lpm run test --affected           # only members affected by recent changes
lpm run test --filter web --no-bail  # keep running selected members after a failure
lpm run build --filter './packages/*' --workspace-concurrency 2
lpm run test --watch              # re-run on file changes
lpm run --env=staging start       # load .env.staging before running
```

## Forwarding arguments [#forwarding-arguments]

Anything after `--` is passed verbatim to the script:

```bash
lpm run dev -- --port 4000 --host 0.0.0.0
# runs: <whatever "dev" expands to> --port 4000 --host 0.0.0.0
```

## Parallel execution [#parallel-execution]

```bash
lpm run -p lint test typecheck
```

Runs all three scripts concurrently, respecting any task dependencies declared in `lpm.json`. Output is buffered per task by default — pass `--stream` for live prefixed output. With `--no-bail`, the runner keeps going past failed tasks and reports the failures at the end.

## Workspaces [#workspaces]

```bash
lpm run build --all                    # every member, topological order
lpm run build --filter web             # one member
lpm run build --filter web --filter api # two members (union)
lpm run build --filter-prod ...shared  # prod graph closure only
lpm run test --affected                # members touched since base branch
lpm run test --affected --base develop # change base branch (default: main)
lpm run test --affected --changed-files-ignore-pattern '**/README.md'
lpm run test --affected --test-pattern '**/*.test.js'
```

`--filter` accepts the [filter grammar](/docs/packages/workspaces): exact name (`foo`), glob (`@scope/*`), combined name/path (`@scope/*{./apps/web}`), path glob (`./apps/*`), forward closure (`foo...`), reverse closure (`...foo`), exclusion (`!foo`).

Full grammar also includes path exact (`{./apps/web}`), git ref (`[origin/main]`), and the dependency/dependent-closure variants `foo^...` and `...^foo`.

`--filter-prod <EXPR>` accepts the same grammar, but closure operators ignore `devDependencies` edges. Use it when a production deploy/build/test selection should include runtime workspace dependents without pulling in test-only packages.

`--all` is mutually exclusive with `--filter`, `--filter-prod`, and `--affected`; filters compose with `--affected` (the affected set is unioned with the filter result).

`--all`, filters, and `--affected` require a workspace.

`--filter core` does **not** match `@babel/core` — substring matching is not supported. Use `--filter '*/core'` for that.

`--fail-if-no-match` makes a typo'd filter exit non-zero — recommended in CI.

`--no-bail` keeps running the remaining selected workspace members after a member fails. The command still exits non-zero after the batch if any selected member failed.

`--workspace-concurrency <N>` caps how many selected workspace members run at once within each topological level. The command reads persistent defaults from `lpm.toml > [workspace].concurrency`, then `~/.lpm/config.toml > workspace-concurrency`, then falls back to the host's available parallelism.

`--changed-files-ignore-pattern <glob>` drops matching paths before `[git-ref]` filters or `--affected` map changed files to workspace members. It also reads project defaults from `lpm.toml > [workspace].changed-files-ignore-pattern`.

`--test-pattern <glob>` marks matching changed files as test-only. Directly changed packages still run, but those packages do not seed dependent fan-out when all their changes match the test pattern. It also reads project defaults from `lpm.toml > [workspace].test-pattern`.

## Caching [#caching]

Task results are cached only when the task opts in via `lpm.json` (`cache: true` plus non-empty `outputs`). A cached task with unchanged inputs replays instantly without re-executing. Bypass the cache with `--no-cache`.

Single-script human output prints a compact stderr header before the script's own output:

```bash
› Running build
    cache    miss
    command  next build

✓ build · success in 4.82s
```

On a cache hit, LPM CLI replays the captured stdout/stderr and reports that the task was restored from cache.

Buffered, streamed-with-prefix, and cache-replayed task output is sanitized before LPM renders it. A child process that receives stdout/stderr directly retains raw terminal ownership so interactive programs and terminal-aware tools keep their normal behavior. See [Terminal output security](/docs/reference/terminal-output) for the full boundary, including JSON semantics.

The local cache lives under `~/.lpm/cache/tasks/`. With `lpm.json > remoteCache.enabled`, LPM CLI checks the hosted cache after the local cache and uploads successful task outputs after the local cache write. Remote outages, 404s, bad signatures, and corrupt artifacts are misses — they do not fail a successful local build.

Manage cache state with [`lpm cache`](/docs/packages/cache). See [Task runner — Remote cache](/docs/dev/task-runner#remote-cache) for setup.

## JSON output [#json-output]

```bash
lpm run build --json
lpm run build --filter web --json
```

`lpm run --json` emits an LPM CLI metadata envelope, even for a single script in a single package. Single-package task output is captured into the task result instead of being passed through as raw stdout. The envelope includes `success`, task counts (`total`, `passed`, `failed`), and `tasks[]` entries with each task name, status, exit code, duration, cache-hit state, and skip reason.

Workspace selections emit the workspace envelope with package counts and per-member task status. If a workspace filter matches nothing and `--fail-if-no-match` is not set, JSON mode still emits a successful zero-package envelope instead of falling back to a human warning.

## Environment files [#environment-files]

```bash
lpm run start --env=staging
```

With `--env=staging`, LPM CLI loads `.env`, `.env.local`, `.env.staging`, then `.env.staging.local`. Without `--env`, it loads `.env`, then `.env.local`.

If the script name resolves to an env mode through `lpm.json`, LPM CLI uses that mode automatically unless you override it with `--env`.

Vault-backed env secrets override file values after dotenv loading.

Runtime-hook env names such as `NODE_OPTIONS`, `LD_PRELOAD`, `LD_AUDIT`, `BASH_ENV`, and `DYLD_INSERT_LIBRARIES` are ignored when they come from env files, env secrets, or env-schema defaults. LPM CLI also strips inherited values for these names before spawning the script.

`--no-env-check` skips environment-variable schema validation if you've declared a schema.

## Watch mode [#watch-mode]

```bash
lpm run dev --watch
```

Re-runs one script in one package on file changes.

If the task declares `inputs` globs in `lpm.json`, only matching file changes retrigger the run. Otherwise, relevant project-file changes retrigger it.

`--watch` is single-package today: it does not support multiple script names or workspace-selection flags like `--all`, `--filter`, `--filter-prod`, or `--affected`. Watch runs fresh on every change; the task cache is not used.

## Flags [#flags]

| Flag                                    | Effect                                                                                            |
| --------------------------------------- | ------------------------------------------------------------------------------------------------- |
| `-p`, `--parallel`                      | Run scripts concurrently (respects task deps from `lpm.json`)                                     |
| `--no-bail`                             | Keep running remaining tasks or selected workspace members after a failure                        |
| `--stream`                              | Live prefixed output instead of buffered per-task in task-graph / parallel runs                   |
| `--all`                                 | Run in every workspace member (topological order); mutually exclusive with filters / `--affected` |
| `--filter <EXPR>`                       | Filter workspace members (repeatable; unions)                                                     |
| `--filter-prod <EXPR>`                  | Filter workspace members with production-only dependency closures                                 |
| `--fail-if-no-match`                    | Exit non-zero if the selected workspace set is empty                                              |
| `--workspace-concurrency <N>`           | Limit concurrent workspace members for `--all`, `--filter`, or `--affected` runs                  |
| `--affected`                            | Only members affected by changes vs `--base`                                                      |
| `--base <REF>`                          | Git base ref for `--affected` (default: `main`)                                                   |
| `--changed-files-ignore-pattern <glob>` | Ignore matching git-diff paths for `--affected` / `[git-ref]` filters                             |
| `--test-pattern <glob>`                 | Treat matching git-diff paths as test-only for `--affected` / `[git-ref]` fan-out decisions       |
| `--no-cache`                            | Bypass the task cache for cache-enabled tasks; ignored in watch mode                              |
| `--no-env-check`                        | Skip env-var schema validation                                                                    |
| `--env=<MODE>`                          | Load `.env`, `.env.local`, `.env.<MODE>`, and `.env.<MODE>.local`                                 |
| `--watch`                               | Re-run one script in one package on file changes                                                  |

Plus the [global flags](/docs/commands#global-flags).

## See also [#see-also]

* [`lpm <file>`](/docs/dev/exec) — run a JS/TS file directly (no script needed)
* [`lpm exec <bin>`](/docs/dev/exec) — explicitly run a project-local binary
* [`lpm dlx`](/docs/dev/dlx) — run a package binary without installing
* [Task runner](/docs/dev/task-runner) — caching, dependencies, `lpm.json` task graph
* [Workspaces](/docs/packages/workspaces) — filter grammar
