Migrating from npm
Convert a package-lock.json project to LPM CLI with rollback safety.
lpm migrate converts an npm project to LPM CLI. It writes a version 12 staging lockfile, then runs an online install by default.
The install writes version 13 with exact package-instance identities. Every changed file has a backup. Use --rollback to restore the original state.
This guide is the migration walkthrough. For the full flag reference, see lpm migrate.
Prerequisites
- LPM CLI installed — see Installation.
- A working
package-lock.jsonin the project root. - A reasonably-clean working tree (commit before migrating, just to be safe).
1. Preview
lpm migrate --dry-runDetects npm, parses package-lock.json, converts to the LPM CLI format, but writes nothing. Reports the package count, any packages that couldn't be converted (with reasons), and the workspace member count.
If anything looks wrong, fix it before doing the real run.
2. Run the migration
lpm migrateWhat runs, in order:
- Pre-flight — confirms
package.jsonexists, refuses to clobber an existinglpm.lock. - Detect, parse, convert — reads
package-lock.json, converts entries to LPM CLI's lockfile shape. - Write — emits a version 12 staging
lpm.lock. If the graph fits the binary format, it also emitslpm.lockb. .npmrc— adds LPM CLI-aware config to.npmrc(or creates one). Backs up the original to.npmrc.backup.- Install — runs an online
lpm install. This step writes version 13 and removes the staginglpm.lockb. - Verify — runs
build+testif those scripts exist, to confirm nothing broke. - CI hint — when a CI platform is detected (
.github/workflows,.gitlab-ci.yml, etc.), prints a hint suggesting you re-run withlpm migrate --cito generate a workflow template. - Summary — what was done, where backups live, and how to roll back.
The migrate flow is non-interactive — every step runs straight through. If lpm.lock already exists, pass --force to overwrite it.
3. Verify
If you used --no-install, run an online install first:
lpm installThen run your usual checks:
lpm install --offline # confirm reproducibility from the new lockfile
lpm test
lpm lint
lpm fmt --checkIf anything's broken, see Rollback below.
4. Commit
git add lpm.lock .npmrc package.json
test ! -f lpm.lockb || git add lpm.lockb
git rm package-lock.json package-lock.json.backup .npmrc.backup # if you don't want them committed
git commit -m "Migrate to LPM CLI"You probably don't want the .backup files in the repo. Add them to .gitignore:
*.backupRollback
If anything goes wrong (or the migration was a mistake):
lpm migrate --rollbackWalks the backups created by the previous run and restores package-lock.json, .npmrc (if it was touched), and .gitattributes to their pre-migration state. Files the migration newly created — lpm.lock, lpm.lockb, any new .gitattributes, and any patch files copied to patches/ — are removed. package.json is only rolled back if the migration mutated it (i.e., when pnpm.* blocks were translated; usually not on the npm path). Safe to run repeatedly.
Optional flags
| Flag | Effect |
|---|---|
--dry-run | Parse + convert only, write nothing |
--force | Overwrite an existing lpm.lock |
-y, --yes | Reserved. The flow is non-interactive today, so this flag is a no-op. It does NOT imply --force. |
--no-install | Convert lockfile only, skip the install step |
--skip-verify | Skip the build + test verification |
--no-npmrc | Don't touch .npmrc |
--ci | Also generate a CI workflow template for the detected platform |
--no-ci | Suppress the CI template hint |
--rollback | Restore from .backup files |
What stays the same
package.json—dependencies,devDependencies,scripts,workspacesare read as-is. No renames, no deletions.node_modules/— gets rebuilt by the install step. The on-disk shape may change from npm's flat tree to LPM CLI's v2 hoisted layout, or to LPM CLI's isolated layout for workspaces and peer-conflict installs; declared imports continue to work because LPM CLI's resolver respects the same semver semantics npm does..npmrc— any existing@scope:registry=lines for private registries survive the migration. The migration additively appends@lpm.dev:registry=https://lpm.dev/api/registry/(unless you pass--no-npmrc); if your.npmrcalready declared that scope, the step is a no-op. LPM CLI honors.npmrcfor routing — see Registries.
What changes
package-lock.json→lpm.lock. The default install writes version 13 and removes the temporary binary companion.node_modules/layout starts hoisted for single packages in LPM CLI's v2 virtual-store layout. Workspaces auto-flip to isolated (pnpm-style symlinks) for phantom-dep catching; force hoisted withlpm install --linker=hoistedorpackage.json > lpm > linker = "hoisted".- New
.gitattributesline:lpm.lockb binary(so git doesn't try to text-merge the binary lockfile).
Common pitfalls
- The lockfile is now strict. An offline or frozen install rejects a version 12 staging lockfile. Run
lpm installonce afterlpm migrate --no-install. - Phantom-dep code breaks under isolated layout. If you imported a package you didn't declare in
dependencies, npm hoisted it intonode_modules/and your code worked anyway. LPM CLI's isolated layout doesn't hoist — undeclared imports become hard errors. Add the missing entries todependencies. - Dependency lifecycle scripts don't run on
lpm installby default. Bare installs run the root project's lifecycle, includingprepare, but dependencypostinstallscripts (esbuild, sharp, etc.) stay blocked until you runlpm rebuildand approve the script-running packages withlpm approve-scripts.
See also
- Migrating from pnpm — same shape, different source lockfile
lpm migrate— full flag reference- Registries — how
.npmrcrouting works after migration - Lockfile — what gets committed and why
lpm install --linker— keeping the flat layout if you need to