Definition
The workspace protocol is a notation used in a monorepo (a layout where multiple packages live together in a single repository) to depend on an internal package by linking directly to its local source — as in "pkg": "workspace:*" — instead of using a version string. At publish time, a workspace-aware package manager rewrites this notation into a real version range before uploading to the registry.
In other words, it wears two faces: a local link during development, and a real version at the moment of publish.
Why it matters
Suppose the package @scope/ui depends on @scope/utils inside a single repository. If you pin @scope/utils to a version like ^1.0.0, then every time you change a single line in utils you have to bump the version and reinstall or relink for the change to show up locally. Development slows down dramatically.
If you write "@scope/utils": "workspace:*" instead, the local source is linked directly and changes are reflected immediately. But if you publish this workspace:* string to npm as-is, an external consumer's package manager cannot interpret workspace:* and their install breaks. That is why the string must be replaced with a real version at publish time, and that replacement only happens through commands that understand the workspace.
How it works
- During development:
installrecords theworkspace:*dependency in the lockfile aslink:../utils, and symlinks the local package intonode_modules. - At publish:
pnpm publish(or yarn) replaces theworkspace:*inpackage.jsonwith the target package's actual published version just before building the tarball. For example:workspace:*→^1.3.0. - Order: You must publish from the leaves of the dependency graph (the lower-level packages) first, so that the lower version referenced by a higher-level package already exists in the registry.
npm publish does not perform this replacement — workspace:* is uploaded raw, producing an uninstallable tarball.
In practice
Before publishing, open the tarball with pnpm pack and visually confirm that the dependency versions in package.json have been replaced with real values rather than workspace:* — this prevents accidents.
Trade-offs
- What you gain: local development speed (instant reflection), no manual version bookkeeping, atomic changes across a single repository.
- What you pay: the publish pipeline gets tied to a workspace-aware manager. The
npm publishhabit, the expectation of OIDC, and the wrong order all become places that break. - Combining it with a version automation tool (a release tool) is convenient, but that adds just as much CI wiring (runners, tokens, ordering).
When not to use
- If there is only one package, or the packages do not depend on each other, the workspace protocol offers no benefit.
- If you are constrained to publish exclusively with
npm publish, you must not useworkspace:*— it will not be rewritten.
Common mistakes
- Publishing with
npm publish:workspace:*is uploaded as-is and external installs break. Usepnpm publish. - Pinning an internal dependency to a nonexistent external version: if
^1.0.0is not in the registry, CIinstallgives a 404. Switch toworkspace:*and relock. - Reversed publish order: publishing the higher-level package first means it cannot find the latest lower-level version. Publish from the leaves first.
- Expecting OIDC:
pnpm publishdoes not support OIDC → without an automation token for publish permission, you get a 403.
Related concepts
- [[library-esm-packaging-dangling-exports]] — a problem that blows up alongside this in the same publish pipeline, caused by a missing export field