To align a dependency across npm packages on a Mac, first compare the version ranges in each workspace’s package.json, decide which common version range fits every package, then update each affected workspace and regenerate the root lockfile. npm workspaces can target packages from the repository root, but they do not provide a built-in command that scans every manifest and automatically makes dependency versions identical.
1. Check that the repository uses npm workspaces
In Terminal, move to the repository root and inspect its configuration:
cd "/path/to/your/repository"
npm --version
npm pkg get workspaces
The root package.json should define the workspace paths, and each package should have its own package.json. npm’s workspace feature links those local packages during installation and lets commands target one or more workspaces by name or path. If npm pkg get workspaces returns nothing, confirm the repository’s package manager and layout before using npm workspace commands. npm Workspaces
2. Compare the dependency declarations
Search the tracked manifests for the dependency you want to align. For example, in macOS Terminal you can use grep without installing an extra tool:
grep -n '"typescript"' package.json packages/*/package.json
Replace typescript with the dependency name. This is a quick text check, so review the matching sections in each manifest to see whether the package is under dependencies, devDependencies, peerDependencies, or optionalDependencies. Those fields describe different roles; do not move a dependency between them just to make the version strings match. For a fuller inventory, inspect each workspace manifest in your editor or use npm’s workspace-aware listing command:
npm ls typescript --workspaces --depth=0
The manifest ranges and the installed tree answer different questions: the first shows what each package permits, while npm ls reports installed dependency state. npm’s lockfile records resolved versions, but it does not replace the acceptable ranges declared in each package.json. npm ls package-lock.json and npm install
3. Choose a compatible version policy
Pick a version that satisfies the consumers’ requirements and the repository’s support policy. A shared version range means the packages express the same allowed set; it does not guarantee that all nested or transitive copies resolve to one installed copy. Check peer dependency requirements and release notes for breaking changes before moving packages across a major version. If consumers need a wider compatibility range, aligning to the same exact string may be inappropriate; agree on an equivalent range policy instead.
For example, to set a development tool to the same exact version in two workspaces named web and api, run this from the root:
npm install --save-dev --save-exact typescript@5.8.3 --workspace=web --workspace=api
Use the version your project has selected; 5.8.3 here is only an example. npm’s install command accepts workspace selectors and saves the package to each selected package manifest. --save-exact writes an exact version rather than npm’s usual range operator. For a runtime dependency, use the appropriate save category, such as --save-prod, instead of --save-dev. npm install
Repeat with additional workspace selectors or run the command for each workspace. Do not assume a root-level install updates every package manifest: explicitly target the packages whose declarations should change. The root package can also be included deliberately with --include-workspace-root when it should declare the same dependency.
4. Reinstall, inspect the diff, and verify
After updating the declarations, run installation at the repository root so npm reconciles the workspace tree and lockfile:
npm install
npm ls typescript --workspaces --depth=0
git diff -- package.json package-lock.json packages/*/package.json
Check that each intended manifest has the agreed declaration and that the lockfile change is expected. Run the repository’s relevant build or test scripts; npm ls alone does not establish that the code works with the selected version. Commit the root package-lock.json when the project tracks it, so team installs can reproduce the resolved tree. npm package-lock documentation
If npm reports an invalid dependency or peer conflict, inspect the package named in the error rather than forcing installation. A workspace may require a different compatible range, or another dependency may impose a peer requirement that needs a deliberate upgrade plan.
When npm dedupe helps
npm dedupe can simplify the installed dependency tree by moving compatible dependencies higher so packages can share them. It does not rewrite direct dependency ranges in package.json, so it cannot align declarations by itself. Use it only after checking that the ranges are compatible, then review the resulting lockfile diff. npm dedupe
The reliable finish is a deliberate policy expressed in each relevant workspace manifest, a regenerated lockfile, and verification of the affected packages. That gives maintainers a clear record of what was aligned and leaves incompatible constraints visible for a separate decision.
Sources
Workspaces — npm
npm install — npm
npm ls — npm
package-lock.json — npm
npm-dedupe — npm