In a monorepo that publishes many packages, what is the difference between giving every package one locked version and versioning each package independently?
answer
- one number for everything, or one each
- republished with no changes
- bumps must cascade to dependents
- workspace links replaced at publish time
- tag as name@version, not just v1.4.0
basics
~20 sLocked (fixed) mode gives every package the same version number and republishes them together on each release. Independent mode bumps and publishes only the packages that changed, each on its own version line, at the cost of far more bookkeeping.
solid answer
~50 sWith a single locked version, the release is one number for the whole repository: bump it, publish every package at that version, tag once. Consumers get a trivially clear compatibility story — `1.4.0` of anything works with `1.4.0` of everything — but every release republishes packages with no changes, so version numbers stop meaning anything about a given package, and a consumer upgrading one dependency is pulled along by unrelated churn. Independent versioning bumps only what changed, so a package's history reflects its own changes and consumers upgrade at their own pace. The bookkeeping is the price: the tool must work out which packages changed, cascade bumps to dependents whose declared ranges no longer resolve, write per-package changelogs, and tag with a name-qualified scheme such as `[email protected]`. Lerna calls these fixed and independent mode; Changesets does the equivalent from per-change intent files.
code
json · 9 lines{
"version": "independent",
"packages": ["packages/*"],
"command": {
"publish": {
"conventionalCommits": true
}
}
}go deeper
Be able to state the distinction: locked means every package shares one version number and is republished together, independent means each package moves only when it changes.
Explain the bookkeeping independent mode requires — attributing changes to packages, cascading bumps to dependents, per-package tags and changelogs — and name the workspace-link rewrite at publish time.
Talk about the release failures each model produces in practice: unpublishable workspace references, dependents pointing at versions that do not exist, and consumers forced through unrelated majors.
Frame it as a contract with consumers rather than a tool setting: who consumes these packages, whether they upgrade as a suite, and whether a grouped model reflects the real coupling better than either pure option.
## Two release models over one commit history A monorepo has one history but potentially fifty published artifacts. The version-numbering question is how that one history maps onto their version lines. **Locked (fixed) versioning.** One version number applies to every package. When you release, everything is republished at the new number, whether or not it changed. This is Lerna's default mode, and the model several large frameworks ship under. **Independent versioning.** Every package carries its own version and moves only when its own contents change. In Lerna this is switched on explicitly: ```json { "version": "independent", "packages": ["packages/*"] } ``` ## What locked versioning gets right - **A trivial compatibility story.** A consumer never has to reason about which combination of your packages works together. Everything at `1.4.0` was built, tested and released as one set. - **Almost no tooling.** One number, one tag, one changelog. The release process is a bump and a publish. - **A single support conversation.** "What version are you on?" has one answer, which matters when many packages are usually consumed together. ## What it costs - **Version numbers stop describing the package.** A package that has not changed in a year sits at the same version as one rewritten last week. `1.9.0 → 2.0.0` on a package with no changes tells a consumer nothing except that *something somewhere* broke compatibility. - **Forced churn for consumers.** Wanting a fix in one package means taking a version bump across the set, and every bump invites the question of what else moved. - **Publish volume.** Fifty artifacts per release, most of them byte-identical to the previous release except for the version field. ## What independent versioning gets right — and what it demands Independent versioning restores the meaning of a version number: a bump on `auth` means `auth` changed. Consumers upgrade the packages they care about, when they care. The demands are real, though, and they are the substance of the interview answer: **1. Deciding what changed.** The tool must attribute commits or explicit change descriptions to packages. Two families exist: derive it from commit history and message conventions, or have contributors declare intent per change — which is what Changesets does, with small files in `.changeset/` that name the affected packages and the bump size, consumed later by `changeset version` and `changeset publish`. **2. Cascading bumps to dependents.** If `auth` goes `2.0.0` and `api` declares a dependency on `^1.0.0` of it, then either `api` is bumped and its range widened, or it is deliberately left on the old line. Getting this wrong is the classic monorepo release bug: a package published referencing a version of a sibling that either does not exist yet or is incompatible with it. **3. Rewriting internal references at publish time.** Inside the workspace, packages reference each other through a workspace link rather than a registry version — the `workspace:*` protocol in pnpm and Yarn is the common form. Publishing must replace that with a real resolvable range, because no consumer outside the repository can resolve a workspace link. A package published with a workspace protocol still in its manifest is simply broken on install. **4. Tags and changelogs per package.** A single `v1.4.0` tag no longer identifies a release; you need name-qualified tags like `[email protected]`, and a changelog per package rather than one at the root. ## The middle ground people actually use Groups. Packages that are genuinely coupled — a core library and its official plugins — share a locked version; unrelated tools version independently. This is more work to configure than either pure model but reflects reality better than both. ## How to choose Ask who consumes the packages and whether they consume them together. - **Consumed as a suite by outside users, upgraded together** — locked. The compatibility guarantee is worth the meaningless version numbers. - **Consumed piecemeal, by different teams, on different schedules** — independent. Forcing unrelated upgrades on a team that wanted one bug fix is a real tax. - **Purely internal, everything always on the tip** — the question mostly evaporates. When every consumer lives in the same repository and builds from source, versions matter far less than the affected-build correctness, and many internal monorepos never publish per-package versions at all. The answer that lands in an interview is that this is a *consumer* question, not a tooling question: the version number is a communication channel with people outside the repository, and you pick the model that says the truest thing to them at a bookkeeping cost you can automate.
- In independent mode, what happens to a package whose only change is that a sibling it depends on was bumped?The release tool cascades: if the declared range on the sibling no longer resolves to the new version, the dependent's manifest is updated and it gets its own bump, usually a patch. Skipping that cascade is the classic release bug — you publish a package pointing at a sibling version that is either unpublished or incompatible, and installs break for consumers even though the repository was green.
- Why must workspace-protocol dependency references be rewritten before publishing?A reference such as `workspace:*` resolves only inside the repository, where the package manager links the local copy. A consumer installing from a registry has no workspace, so the reference is unresolvable. Publishing must substitute the real version range the workspace link stood for; publishing a manifest with the protocol still in it produces a package nobody can install.
- What does locked versioning cost the consumer of a single package?Forced churn. To take one fix they accept a version bump across every package in the set, including a possible major bump caused by an unrelated package's breaking change. And the number itself carries no information about their package, so they cannot tell from the version whether anything they depend on actually changed.
saying these in an interview costs you the question
- Thinks independent versioning removes the need to cascade bumps
- Publishes manifests still carrying workspace protocol references
- Uses one v1.4.0 tag for independently versioned packages
- Claims locked versioning has no cost for consumers
- Treats version choice as tooling rather than a consumer contract