Publish safely
Recover from a bad release
Use deprecation, a fixed follow-up version, dist-tags, and clear communication instead of rewriting history.
Published npm versions are normally immutable. You cannot overwrite @acme/[email protected] in place. Recovery means steering consumers toward a known-good release.
Imagine 1.2.0 shipped with a regression: empty strings throw instead of returning ''. Downloads are already happening. Here is the sequence I follow.
1. Stop promotion
Do not move dist-tags forward. If latest already points at the bad version, plan a fix before you touch tags again.
2. Deprecate with a precise message
npm deprecate @acme/[email protected] "Broken empty-string handling. Upgrade to >=1.2.1"
Consumers who install fresh see the warning during npm install. Existing lockfiles still resolve until they upgrade.
3. Ship a tested fix as a new version
Fix the bug, run the full release gate, bump the patch version, and publish:
npm version patch
npm publish --access public
4. Move latest only after verification
npm dist-tag add @acme/[email protected] latest
npm dist-tag ls @acme/slugify-title
Output should show latest: 1.2.1.
5. Tell affected users
Post a short note: affected range, symptom, fixed version, and workaround if they cannot upgrade immediately.
What not to do
Do not reuse the same version number. Do not silently retag latest without a fixed release. Unpublish is limited to very new packages with almost no downloads and creates broken installs for anyone who cached the tarball.
Write the recovery timeline before you need it. When something breaks at midnight, a checklist beats improvisation.
If only latest was affected and older versions are fine, say so in the deprecation message. Pinning consumers on 1.1.x should not look like a crisis when 1.1.9 still works.
After recovery, add a release-gate test that would have caught the bug. A missing consumer smoke case is often the real root cause, not npm itself.
Lesson completed