LPM CLI

lpm tidy

Find unused dependencies and undeclared imports, then remove unused declarations and update the installed tree.

Find dependency declarations that your package does not use, and imports that lack a declaration.

lpm tidy [OPTIONS]

Quickstart

lpm tidy
lpm tidy --fix
lpm tidy

The default command reports findings without changing files. --fix removes unused declarations and reinstalls the remaining dependencies.

ModeEffect
lpm tidyReport unused declarations and undeclared package imports.
lpm tidy --fixRemove fixable unused declarations, then update the lockfile and installed tree.
lpm tidy --jsonEmit a structured report for scripts or CI.

The command acts on the nearest directory with a package.json, as lpm install does. From a subdirectory, it prints the directory it chose. It does not process every workspace member.

Examples

# Inspect before removing dependencies
lpm tidy --json

# Apply removals without a confirmation prompt
lpm tidy --fix

# Gate CI without changing files
lpm tidy --json > dependency-report.json

# Review one workspace member
cd packages/web
lpm tidy

A clean package exits with code 0. Remaining findings exit with code 1, including after --fix.

Configuration

There is no dedicated tidy section in lpm.json. You can define an uncached task:

lpm.json
{
  "tasks": {
    "deps:check": {
      "command": "lpm tidy",
      "cache": false
    }
  }
}
lpm run deps:check

command defines the invocation. cache: false reruns the inspection instead of reusing an earlier result.

Tools referenced by lpm.json service and task commands count as used. Node loader options, such as node --import=tsx, also retain their packages. An explicit lpm.json task command takes precedence when lpm run selects a command.

Ignore intentional dependencies

Use [tidy] in lpm.toml for dependencies loaded through framework conventions or other usage that static inspection cannot detect.

lpm.toml
[tidy]
ignore-unused = ["eslint-config-next", "@types/node"]
ignore-phantom = ["test-harness"]
ignore-paths = ["generated/**", "src/fixtures/**"]
KeyTypeEffect
ignore-unusedString or string array.Suppress unused findings that match a package-name glob.
ignore-phantomString or string array.Suppress undeclared imports that match a package-name glob.
ignore-pathsString or string array.Skip matching source files and directories before reading or parsing them.

Paths are relative to the package directory. Invalid patterns or malformed tidy configuration stop the command before a fix.

There are no CLI overrides or one-run bypass flags for these lists. To inspect an ignored item, remove its matching entry and rerun the report.

What counts as used

LPM CLI checks these sources:

  • Imports in .js, .jsx, .ts, .tsx, .mjs, .cjs, .mts, and .cts files, including TypeScript declarations.
  • Root entrypoints, scripts, tests, and other source directories within the package.
  • package.json scripts and lpm.json task or service commands.
  • Installed executable names declared by a dependency's bin field.
  • Common tool configuration files, such as eslint.config.js, vite.config.ts, tsconfig.json, and webpack.config.js.
  • Matching type packages, such as @types/react for react and @types/node for Node built-in imports.

The scan recognizes static imports, re-exports, require(), and dynamic imports with literal package names. It also recognizes TypeScript import types, import-equals declarations, and /// <reference types="..." /> directives.

Other comments, ordinary strings, relative imports, and recognized local aliases do not count as package usage.

Script and configuration checks are conservative. Common tool families can remain declared when related scripts or configuration exist. An unused report still needs review before removal.

Scan scope and limits

The source scan skips nested packages with their own package.json, unless a published entrypoint points into that package. It also skips linked source paths, hidden directories, node_modules, and known build-output directories.

If main, module, types, typings, exports, or bin points into dist or build, that output directory joins the scan.

The limits are 10,000 source files, 2 MiB per file, 64 MiB total, 64 directory levels, 100,000 directory entries, and 100,000 imports.

An unreadable input, special file in place of configuration, invalid source syntax, or exceeded limit stops the command. It does not apply removals from a partial scan.

For generated or fixture files that do not describe package usage, add an explicit ignore-paths entry. Keep required source files in the scan.

Report mode uses local files. It does not query a registry. Installed manifests improve executable detection, but a missing installed dependency does not require an install first.

Apply removals

lpm tidy
lpm tidy --fix

The fixer removes unused entries from dependencies, devDependencies, and optionalDependencies. It then updates lpm.lock and node_modules/.

This install can contact the configured registries and run the root package's install lifecycle. The normal dependency script policy still applies.

peerDependencies remain report-only because they can describe a contract for consumers. Undeclared imports also remain report-only.

To add a required undeclared package, choose its version and save policy with lpm install:

lpm install left-pad
lpm tidy

For an intentional peer declaration, review it and add the package name to ignore-unused. Rerun the report after application changes.

There is no separate dry-run flag. The default report is the preview. --fix does not prompt for confirmation.

Recovery

Before writing, the fixer checks that package.json still matches the analyzed bytes. A concurrent manifest change stops the operation.

A failed reinstall restores the saved manifest and lockfiles. The transaction does not restore every change to node_modules/ or script-created files.

If installation fails, correct the reported cause and restore the installed tree:

lpm install
lpm tidy

Review the manifest diff and run your package tests after a successful fix. Static inspection cannot identify every dynamic dependency use.

JSON output

lpm tidy --json
lpm tidy --fix --json

Both modes emit one report. Nested install details do not precede the JSON document.

FieldMeaning
successNo findings remain.
fixedThe invocation selected --fix. This does not mean that every finding was fixed.
manifestThe package manifest path.
countsDeclared and imported packages, unused and undeclared findings, ignored findings, removals, and remaining findings.
unusedUnused declarations with their section, version specifier, reason, and fixable status.
phantomsUndeclared imports with a file, line, and import count.
removedDeclarations removed by this invocation.
ignoredFindings suppressed by package-name ignore rules.
elapsed_msElapsed command time in milliseconds.

phantoms[].available_via can explain that an undeclared import currently resolves through a transitive dependency. That availability does not make it a direct dependency.

After a fix, unused and counts.remaining describe unresolved findings. Parse errors and installation failures use the standard error envelope.

Flags

FlagEffect
--fixRemove fixable unused declarations and reinstall.
--jsonEmit a structured report, with a nonzero status when findings remain.

See global flags for shared options.

See also

  • lpm install — add dependencies or restore the installed tree.
  • lpm uninstall — remove a specific dependency.
  • lpm audit — inspect vulnerabilities and source risks.
  • lpm.toml — project configuration and tidy ignore lists.
  • lpm.json — reusable task and service commands.