Retire a shared internal library in stages: find every consumer, announce a replacement and end date, mark the package deprecated, track migration weekly, and only then archive the code and remove publish access. Skipping the tracking step is how services end up running unpatched code nobody owns.
Step by step
- Find consumers. Use lockfiles, SBOMs and a code search across repositories. Include copied code, which will not appear in a package graph.
- Choose the replacement. Another library, a standard package or a service. Write a short migration guide with before and after examples.
- Set the dates. An announcement date, a freeze date after which only security fixes ship, and a removal date.
- Announce. Send to owners of every consuming service, not to a general list.
- Deprecate in the registry. npm documents that deprecating a package version or range shows a warning to everyone installing it. Add the replacement name in the message. See what an npm deprecation message should say.
- Open migration tickets in each team's queue with the guide linked.
- Track weekly. Count remaining consumers and report to team leads.
- Remove. Archive the repository, revoke publish rights, and delete tokens.
Timeline guide
| Phase | What happens | Typical length |
|---|---|---|
| Announce | Notice, guide, tickets | Day 0 |
| Freeze | Security fixes only | Weeks to months, based on consumers |
| Deadline | Last security fix | Published date |
| Archive | Read only, access removed | After count reaches zero |
Pick the lengths from your own consumer data, not from a template.
What the semantic versioning rules say
Deprecation is a normal part of development. The specification advises updating documentation to let users know, issuing a release with the deprecation, and keeping the old functionality until a major version removes it. Apply the same thinking to a whole library.
Keep security fixes flowing until the end
A deprecated library is still a library. If a vulnerability appears during the freeze, ship the fix and announce it. The cost is small compared with leaving consumers exposed.
Handle the stragglers
When the date passes and a consumer has not moved, escalate to their engineering manager with the service name and the risk. If the service truly cannot move, record a time limited exception with an owner, or consider forking with a clearly named new owner.
Verify it is gone
Scan again after the deadline to confirm nothing still resolves the retired library, and remove it from the ownership map.
Safeguard can help with the inventory side: its SBOM and dependency scanning shows which services pull in a given internal library, and you can run a free scan at gold.safeguard.sh/scan.
Quick check
Do we delete the package from the registry?
Usually not at first. Deprecate, wait for consumers to move, then archive. Deleting early breaks builds.
How do we find copy pasted usage?
Search code for distinctive function names or imports across all repositories, and ask teams in the announcement.
Sources
Last reviewed: 19 October 2026.