npm 20 ๐ Unpublishing, Deprecating, and Transferring Packages
Package lifecycle management extends beyond publishing. A maintainer eventually faces one of three decisions: remove a package entirely, mark it as no longer recommended while keeping it installable, or hand it to someone else. npm provides a distinct command for each, and the registry’s policies determine which commands are even permitted. The default recommendation from npm is deprecation, not unpublishing, because unpublishing breaks every project that depends on the package . Transferring ownership is the third option, used when the package still has value but the current maintainer can no longer support it.
Key point: Unpublishing is heavily restricted because it breaks the ecosystem. A package published more than 72 hours ago can only be unpublished if it has no dependents, fewer than 300 weekly downloads, and a single owner . If any of those conditions fail, deprecation is the only available path.
Why these three operations exist
The ecosystem stability problem. The left-pad incident in 2016 demonstrated what happens when a widely depended-upon package disappears from the registry. Thousands of builds broke because a single maintainer unpublished an 11-line function . npm responded by tightening unpublish rules: within 72 hours of publishing, a package can be removed if no other package depends on it. After 72 hours, the criteria become much stricter, and the default recommendation is deprecation .
The maintenance transition problem. A maintainer who loses interest in a package has an obligation to the users who depend on it. Deprecation communicates that the package is no longer supported without breaking existing installs. The deprecation message appears in the terminal when a user installs the package, on the npm website, and removes the package from search results if the entire package is deprecated . This gives users time to migrate without breaking their builds immediately.
The succession problem. A package that is still useful but whose maintainer can no longer support it should be transferred, not abandoned. The npm owner command manages the list of users who can publish new versions and modify metadata . Transferring ownership is a two-step process: add the new owner, then remove yourself. The new owner must accept an invitation before the transfer is complete .
a. Unpublishing: Removing Versions or Entire Packages
npm unpublish removes a package version or an entire package from the registry. The command deletes the registry entry and the tarball. Once a version is unpublished, that specific name and version combination can never be reused; a new version number must be published instead .
# Unpublish a single version
npm unpublish my-package@1.0.0
# Unpublish an entire package (requires --force in some versions)
npm unpublish my-package --force
The registry enforces the 72-hour window and the dependency/download/owner criteria. If the package does not meet the criteria, the command fails, and the error directs the maintainer toward deprecation . Unpublishing an entire package also imposes a 24-hour waiting period before any new version of that package can be published .
The consequences of unpublishing are permanent. There is no undo. The version is gone from the registry, and every lockfile that references it will fail to install unless the package is mirrored elsewhere. This is why the command is restricted and why deprecation is the recommended alternative.
b. Deprecating: Warning Without Breaking
npm deprecate updates the registry entry to include a deprecation warning. The package remains installable, but the warning is displayed during installation and on the package page. This is the recommended path for packages that are no longer maintained or that have been superseded by another package .
# Deprecate an entire package
npm deprecate my-package "This package is no longer maintained. Use new-package instead."
# Deprecate a specific version or range
npm deprecate my-package@"< 2.0.0" "Critical bug fixed in 2.0.0"
The deprecation message can be any string, and the version specifier accepts semver ranges. The command requires the maintainer to be a package owner . To reverse a deprecation, the message argument is replaced with an empty string ("") .
Deprecating an entire package removes it from npm search results and displays the warning on the package page. Individual versions can be deprecated with version-specific messages. The distinction matters: deprecating a range warns users of those versions without affecting newer versions that are still supported.
c. Transferring: Adding and Removing Owners
The npm owner command manages package maintainers. The ls subcommand lists current owners. The add subcommand sends an invitation to a new maintainer. The rm subcommand revokes access immediately .
# List current owners
npm owner ls my-package
# Add a new owner (sends an invitation)
npm owner add newuser my-package
# Remove yourself after the new owner accepts
npm owner rm olduser my-package
The transfer is not complete until the new owner accepts the invitation. The rm command should only be run after the invitation is accepted; otherwise, the package may be left without an active maintainer . Scoped packages cannot be transferred to another user account or organization because the scope is tied to the account name. A new package must be created in the new scope instead .
For packages that are no longer maintained but still have dependents, npm provides a transfer path to the @npm user account. This removes the package from the maintainer’s profile and places it under npm’s control. Once transferred to @npm, the package can no longer be updated by the original maintainer .
Complete Example Session
# ============================================
# PART 1: CHECK UNPUBLISH ELIGIBILITY
# ============================================
# Check the package's current state
npm view my-package time.modified
npm view my-package dependents
# If published >72 hours ago, check criteria
# ============================================
# PART 2: ATTEMPT UNPUBLISH (WILL FAIL IF INELIGIBLE)
# ============================================
npm unpublish my-package@1.0.0
# If the package has dependents or exceeds download limits,
# the registry returns an error and suggests deprecation
# ============================================
# PART 3: DEPRECATE INSTEAD
# ============================================
# Deprecate the entire package with a migration message
npm deprecate my-package "No longer maintained. Migrate to new-package."
# ============================================
# PART 4: VERIFY THE DEPRECATION
# ============================================
# Install the package to see the warning
npm install my-package
# npm warn deprecated my-package@1.0.0: No longer maintained...
# ============================================
# PART 5: DEPRECATE A SPECIFIC RANGE
# ============================================
# Warn users of vulnerable versions only
npm deprecate my-package@"< 1.5.0" "Security fix in 1.5.0"
# ============================================
# PART 6: UNDEPRECATE IF NEEDED
# ============================================
npm deprecate my-package ""
# ============================================
# PART 7: TRANSFER OWNERSHIP
# ============================================
# Add the new maintainer
npm owner add newmaintainer my-package
# New maintainer accepts the invitation via email
# ============================================
# PART 8: VERIFY OWNER LIST
# ============================================
npm owner ls my-package
# Should show both old and new owner
# ============================================
# PART 9: REMOVE YOURSELF
# ============================================
npm owner rm oldmaintainer my-package
# Access revoked immediately
# ============================================
# PART 10: TRANSFER TO @NPM (IF NO SUCCESSOR)
# ============================================
npm owner add npm my-package
npm owner rm oldmaintainer my-package
# Package is now under npm's control; cannot be updated
The ten parts trace the decision tree: check eligibility, attempt unpublish, fall back to deprecation, and transfer ownership when a successor exists. The deprecation path is the most common outcome because the unpublish criteria are rarely met for packages that have been public for more than three days.
Quick Reference
Unpublish Eligibility
| Condition | Within 72 Hours | After 72 Hours |
|---|---|---|
| No dependents | Required | Required |
| Weekly downloads | No limit | < 300 |
| Owners | No limit | Single owner |
| 24-hour republish wait | Yes | Yes |
Command Comparison
| Command | Effect | Reversible |
|---|---|---|
npm unpublish pkg@version | Removes version permanently | No |
npm deprecate pkg "msg" | Adds warning, keeps installable | Yes ("") |
npm owner add user pkg | Invites new maintainer | Yes (rm) |
npm owner rm user pkg | Revokes access immediately | Yes (add) |
Deprecation Syntax
| Command | Scope |
|---|---|
npm deprecate pkg "msg" | Entire package |
npm deprecate pkg@1.0.0 "msg" | Single version |
npm deprecate pkg@"< 2.0.0" "msg" | Version range |
npm deprecate pkg "" | Undeprecate |
Ownership Commands
| Command | Purpose |
|---|---|
npm owner ls pkg | List maintainers |
npm owner add user pkg | Invite new maintainer |
npm owner rm user pkg | Revoke access |
npm owner add npm pkg | Transfer to npm |
Best Practices
โ Do This:
# Deprecate before unpublishing, unless the package was just published
npm deprecate my-package "Use new-package instead" # โ
# Provide a migration path in the deprecation message
npm deprecate my-package "Migrate to new-package@2.x" # โ
# Add the new owner before removing yourself
npm owner add newuser my-package && npm owner rm olduser my-package # โ
# Check eligibility before attempting unpublish
npm view my-package dependents # โ
โ Don’t Do This:
# Unpublish a package that has dependents
npm unpublish my-package --force # fails if dependents exist # โ
# Use unpublish to "fix" a bad release
# Deprecate or publish a new version instead # โ
# Remove yourself before the new owner accepts
npm owner rm olduser my-package # leaves package without maintainer # โ
# Assume a version can be republished after unpublish
# The name@version combination is permanently consumed # โ
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Unpublish fails after 72 hours | Package has dependents or too many downloads | Deprecate instead |
| Cannot republish after unpublish | Version combination is permanently consumed | Bump the version number |
| Deprecation warning not visible | Package name was mistyped | Verify with npm view pkg deprecated |
| Transfer incomplete | New owner did not accept invitation | Check email and owner list |
| Cannot transfer scoped package | Scope is tied to account name | Create new package in new scope |
Real-World Examples
1. Unpublish Single Version
npm unpublish my-package@1.0.0
2. Unpublish Entire Package
npm unpublish my-package --force
3. Deprecate Entire Package
npm deprecate my-package "No longer maintained"
4. Deprecate Version Range
npm deprecate my-package@"< 1.5.0" "Security fix in 1.5.0"
5. Undeprecate
npm deprecate my-package ""
6. List Owners
npm owner ls my-package
7. Add Owner
npm owner add newuser my-package
8. Remove Owner
npm owner rm olduser my-package
9. Transfer to npm
npm owner add npm my-package && npm owner rm olduser my-package
10. Check Deprecation Status
npm view my-package deprecated
Visual
The Decision Tree
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ PACKAGE NO LONGER NEEDED โ
โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ Published < 72h โโโโโโบ Unpublish allowed if no dependentsโ
โ โ and no deps? โ โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โ NO โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ Has dependents โโโโโโบ Deprecate only โ
โ โ or >300 dl/wk? โ โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โ NO โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ Single owner? โโโโโโบ Unpublish allowed โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ Has successor? โโโโโโบ Transfer ownership โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โ NO โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ Deprecate or โ โ
โ โ transfer to npm โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ Deprecation is the default recommendation. โ
โ Unpublishing is the exception. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Deprecation vs. Unpublish
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ DEPRECATE UNPUBLISH โ
โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ Package remains โ โ Package removed โ โ
โ โ installable โ โ from registry โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ Warning on โ โ No warning; โ โ
โ โ install and โ โ install fails โ โ
โ โ package page โ โ โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ Reversible โ โ Permanent โ โ
โ โ (empty string) โ โ (no undo) โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ Safe for โ โ Breaks โ โ
โ โ dependents โ โ dependents โ โ
โ โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ npm recommends deprecation. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Ownership Transfer Flow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ CURRENT OWNER โ
โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ npm owner add โโโโโโบ Invitation sent to new user โ
โ โ newuser pkg โ โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ New user โโโโโโบ Accepts invitation โ
โ โ checks email โ โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ npm owner ls โโโโโโบ Both owners listed โ
โ โ pkg โ โ
โ โโโโโโโโโโฌโโโโโโโโโ โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ npm owner rm โโโโโโบ Old owner removed โ
โ โ olduser pkg โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ Do not remove yourself before the new owner accepts. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Deprecation Message Visibility
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ AFTER npm deprecate pkg "message" โ
โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ npm install pkg โโโโโโบ Warning in terminal โ
โ โ โ "npm warn deprecated pkg@x: msg" โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ npmjs.com/ โโโโโโบ Red message on package page โ
โ โ package/pkg โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ npm search โโโโโโบ Package removed from results โ
โ โ (entire pkg) โ if entire package deprecated โ
โ โโโโโโโโโโโโโโโโโโโ โ
โ โ
โ The package remains installable. โ
โ The warning is the signal to migrate. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| Unpublish window | 72 hours if no dependents |
| Unpublish after 72h | No dependents, <300 weekly downloads, single owner |
| Version reuse | Never; name@version is permanently consumed |
| Republish wait | 24 hours after unpublishing entire package |
| Deprecate command | npm deprecate pkg "message" |
| Undeprecate | npm deprecate pkg "" |
| Owner list | npm owner ls pkg |
| Add owner | npm owner add user pkg |
| Remove owner | npm owner rm user pkg |
| Transfer to npm | npm owner add npm pkg then npm owner rm user pkg |
Key takeaways:
- Deprecation is the default recommendation; unpublishing is the exception. npm’s documentation states explicitly that deprecation should be preferred because unpublishing removes the package entirely and breaks every project that depends on it . The 72-hour rule and the download/dependency/owner criteria exist to limit the damage that unpublishing can cause.
- The 72-hour window is the only time a package can be unpublishable without meeting the stricter criteria. After 72 hours, the package must have no dependents, fewer than 300 weekly downloads, and a single owner. Most packages that have been public for more than three days do not meet these criteria, which is why deprecation is the common path .
- Deprecation is reversible and non-breaking. The package remains installable, but the warning appears during installation and on the package page. The message can direct users to a replacement. An empty string (
"") removes the deprecation . - Ownership transfer is a two-step process. Add the new owner first, wait for the invitation to be accepted, then remove yourself. Removing yourself before the new owner accepts leaves the package without a maintainer .
- Scoped packages cannot be transferred between accounts. The scope is tied to the account name. A scoped package must be recreated in the new scope rather than transferred .
Remember: The choice between unpublishing, deprecating, and transferring is determined by the package’s role in the ecosystem. A package with no dependents and a short history can be removed. A package with dependents should be deprecated with a clear migration message. A package that still has value but no maintainer should be transferred. The registry’s policies enforce these distinctions because the alternativeโunrestricted deletionโproduces the left-pad problem at scale. The commands are simple; the judgment about which one to use is the skill.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!