Upgrade from the bottom of the dependency graph upward: shared tooling and design tokens first, then the component library, then the apps that use it. Each layer is tested before the next consumes it, so a failure points to one change instead of a pile.
Why order matters
In a monorepo with a design system, packages depend on each other. Apps import the component library, which imports tokens and utilities. If you update all of them in one pull request, a failing test could come from any layer, and the review is too large to read carefully.
Sequencing keeps each change small. It also keeps the shared packages stable for the apps that depend on them, so you are never upgrading an app against a library that is itself half moved.
A sensible sequence
| Step | Layer | Examples | Gate before moving on |
|---|---|---|---|
| 1 | Build and test tooling | Bundler, linter, test runner | Library and apps still build |
| 2 | Leaf packages | Tokens, icons, utilities | Their own tests, visual tests of the library |
| 3 | Host library bump | UI framework, router | Library tests on the new host, peer range reviewed |
| 4 | Component library | Third party UI dependencies | Unit, visual and interaction tests, scan |
| 5 | Apps, smallest first | App specific dependencies | App tests and a staging deploy |
| 6 | Apps, largest last | Same | Same, with monitoring on release |
Step 3 deserves care. Raising the host version usually forces a decision on the peer range, covered in how wide should a design system's peer dependency range be.
How to run it
- Draw the graph from workspace metadata. Many package managers can print workspace dependencies; the npm workspaces documentation describes how packages are linked in one tree.
- Open one pull request per layer, each based on the previous merged one, or use a stacked approach if your tooling supports it.
- Keep the lockfile change in the same pull request as the manifest change, so the review sees what truly moved.
- Run the whole workspace test suite at each step, not only the changed package. Failures in dependents are the point of the exercise.
- Tag a release after the library step so apps update to a known version rather than to the main branch.
Handling urgent security bumps
A security update to a leaf package can jump the queue. Make the minimal bump, run the full suite, and release the library so apps can follow. Do not combine it with planned upgrades. If you need a repeatable way to group routine bumps without hiding risk, see how to group dependency updates without hiding risk.
Mistakes to avoid
Updating apps before the library is released leads to apps that reference unreleased behavior. Updating everything on a Friday before a freeze leaves no room to roll back. For freezes, see pause dependency updates before a release freeze.
Safeguard's dependency scanning covers workspace lockfiles, so each step in the sequence can be checked for new vulnerable packages before you move on. A free scan is at gold.safeguard.sh/scan.
Quick check
Is it ever fine to update everything in one pull request?
For a tiny workspace with fast tests, yes. For a shared library used by many apps, split by layer.
Where do security fixes fit in the sequence?
They jump the queue as a minimal change at the layer where the package lives, followed by a library release.
Sources
Last reviewed: 19 October 2026.