Migrating from npm
Convert a package-lock.json project to LPM CLI with rollback safety.
lpm migrate converts an npm project to LPM CLI in one command. It detects the source package manager, parses package-lock.json, writes lpm.lock plus lpm.lockb when the graph fits the binary format, optionally configures .npmrc, runs lpm install against the new lockfile, and (optionally) verifies that build + test still pass. Every file it touches is backed up first — --rollback restores 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
lpm.lockand, when supported by the binary format,lpm.lockb. Backs uppackage-lock.jsontopackage-lock.json.backup. .npmrc— adds LPM CLI-aware config to.npmrc(or creates one). Backs up the original to.npmrc.backup.- Install — runs
lpm installagainst the new lockfile (lockfile fast-path, no re-resolution). - 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
After migration, run a fresh install + 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.lockpluslpm.lockbwhen the graph fits the binary format. Commitlpm.lockalways andlpm.lockbwhen present.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.
lpm install --offlinewill fail on any drift betweenpackage.jsonandlpm.lock. Whichever wins, runlpm install(without--offline) once after migration to settle them. - 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