A dependency exit plan is a short written answer to one question: if this package became unusable tomorrow, what would we do and how long would it take? It names a replacement or fork route, the code that touches the package, the trigger to start, and who owns the work.
Why write one at adoption time
Packages become unusable for ordinary reasons. The maintainer stops, the license changes, the registry removes it, or a malware advisory lands. The worst moment to design a migration is during the incident.
You do not need a plan for every transitive dependency. Write one for direct dependencies with high blast radius and for packages with a low bus factor. See how to calculate the bus factor.
What it should contain
| Section | Content |
|---|---|
| Where it is used | Modules and services that import the package |
| Seam | The wrapper or interface that isolates it |
| Alternatives | Replacement libraries, or the option to vendor |
| Fork readiness | Can your team read and maintain the source? |
| Triggers | Events that start the plan |
| Time estimate | Rough effort in days, with a reviewer's name |
| Owner | One named person or team |
| Stop-ship rule | What happens if a malware advisory appears |
Triggers worth defining
- A malware advisory. The GitHub Advisory Database says malware advisories have no fix version, so the only safe step is to stop using the package. The plan should say who removes it, who rotates credentials, and how fast.
- A change in registry owners with no explanation.
- Long inactivity combined with an open security report. Scorecard's Maintained check rates activity as high risk, which is a reason to watch it.
- A license change that conflicts with your policy.
Make exit cheap by design
- Wrap the package behind your own small interface so only one module knows its API.
- Keep a test suite that exercises the interface, so a replacement can be checked fast.
- Prefer packages with standard formats over those with proprietary ones.
- For tiny helpers, consider vendoring the source with its license notice kept intact.
- Pin versions so you can reproduce what ran before.
Test it once
Pick one low-risk package and run the plan as a drill. Measure the time. Teams usually find that the seam they assumed does not exist, and that is a cheap discovery to make on a quiet day.
Connect the plan to your adoption record and to the re-review triggers.
An example entry
A short entry might read: used in the import service only, wrapped by one module, replacement candidates identified, estimate of three engineer days, owner is the platform team, trigger is any malware advisory or loss of registry ownership clarity. That is about forty words, and it turns a vague worry into a plan someone can act on. Store it with the adoption record so the two stay in sync.
Safeguard can help here. Its SBOM and dependency scanning, reachability analysis and policy gates cover the checks that should repeat after adoption, and the free scan at gold.safeguard.sh/scan shows what a project already depends on.
Quick check
How long should an exit plan be?
A few lines in the adoption record is enough for most packages. Only critical ones need a longer document.
Is vendoring always the exit?
No. It works for small, stable code your team can maintain. For large packages, a replacement is more realistic.
Sources
Last reviewed: 19 October 2026.