Versioning

What 0.x means in practice, how the packages of the family are tied together by versions, and what the library does not promise yet.

Machine-translated, not yet reviewed. Read the original

An adopter’s question is not “what is the current version” but “how long will this version live”. The honest answer today: no support window is declared. Below is what exists instead, which of it is checkable, and what to do while there is no promise.

While it is 0.x

The library follows Semantic Versioning, and before 1.0 that means exactly one thing: a minor release may break compatibility. Not “in theory” — it has already happened. Version 0.41.0 moved GrCodeBlock out of the core into @feugene/granularity-code, and the @feugene/granularity/components/GrCodeBlock subpath disappeared:

diff
- import { GrCodeBlock } from '@feugene/granularity'
+ import { GrCodeBlock } from '@feugene/granularity-code/components/GrCodeBlock'

The reason is named in the changelog and it is about 1.0: taking something out of a frozen core costs a major, so moves of that kind are made before the freeze rather than after it.

On a zero major, ^ and ~ mean the same thing. ^0.41.0 expands to >=0.41.0 <0.42.0 — the same range as ~0.41.0. That is, the package manager already pins the minor for you: an update to 0.42 takes a deliberate action rather than arriving with an install.

Every package is versioned on its own

The family has no shared version, and that is not an oversight. The core and the companions run on different cycles: @feugene/granularity-code lives on 0.1.x while the core walks towards 0.42 — and an extra major in a companion for the sake of a core release would mean an update with not a single change behind it.

Three things follow, and all three are visible in the repository:

  1. Every package has its own changelog. There is deliberately no shared changelog at the root — the changelogs on this portal are assembled from them.
  2. Every package has its own tag. The core is released with a vX.Y.Z tag, a companion with <directory-name>-vX.Y.Z, for instance granularity-charts-v0.11.0.
  3. Publishing happens from the tag. Pushing a tag triggers publication to npm with --provenance and to GitHub Packages: the released artefact has traceable provenance, and your scanner verifies it rather than us.

The compatibility matrix

A companion declares which version of the core and of the preset it works with — not in words but as a range in peerDependencies. Your package manager reads it by itself and refuses to assemble an incompatible pair. Here is the same range in readable form:

PackageCore @feugene/granularityPreset @feugene/unocss-preset-granularVue
@feugene/granularity-charts>=0.38.0 <1.0.0>=0.13.0 <1.0.0^3.5.0
@feugene/granularity-chrono>=0.38.0 <1.0.0>=0.13.0 <1.0.0^3.5.0
@feugene/granularity-code>=0.40.0 <1.0.0>=0.16.0 <1.0.0^3.5.0
@feugene/granularity-dashboard>=0.38.0 <1.0.0>=0.13.0 <1.0.0^3.5.0
@feugene/granularity-datasource^3.5.0
@feugene/granularity-devtools>=0.38.0 <1.0.0^3.5.0
@feugene/granularity-editor>=0.38.0 <1.0.0>=0.13.0 <1.0.0^3.5.0
@feugene/granularity-forms-schema>=0.38.0 <1.0.0>=0.13.0 <1.0.0^3.5.0
@feugene/granularity-media>=0.38.0 <1.0.0>=0.13.0 <1.0.0^3.5.0
@feugene/granularity-test-kit>=0.13.0 <1.0.0^3.5.0
@feugene/unplugin-granularity>=0.38.0 <1.0.0

A dash means the package does not declare that dependency at all: granularity-datasource knows about neither the core nor the preset — it is about data rather than markup — and test-kit works with any core, because it checks CSS and the DOM rather than importing components.

The upper bound is one and the same everywhere — <1.0.0. It says not “we are compatible with everything below one” but “beyond that there are no promises”: 1.0 will redefine the contract, and the ranges will be rewritten with it.

The table is not typed by hand but verified against the manifests on every build: a range that has diverged from a companion’s package.json fails the portal’s build. It is verified, though, against the tag the library submodule is pinned to — not against what sits in npm this very second. The source of truth is the peerDependencies of the installed package.

Environment requirements

WhatVersionWhere from
Node>=22engines in every package of the family
Vue^3.5.0a peer dependency
Module formatESM only"type": "module", there is no CommonJS build

Those three lines are part of compatibility too, and they change by the same rules: raising the lower bound of Node is a breaking change, and before 1.0 it may arrive in a minor.

What will happen at 1.0

Before 1.0 there is no versioning of the documentation: there is only /docs, without prefixes. Premature versioning doubles the work and confuses the search — an archive with no readers costs exactly as much as a living section.

With the 1.0 release the following turns on:

  • the current tree is copied to /v0/, marked with an “archive” banner and given a rel="canonical" to its current counterpart;
  • archive pages that do have a current counterpart leave the index;
  • a version switcher appears in the documentation header next to the package version.

The version in the header is read from the core manifest at build time and is never typed by hand — that rule is already in force, well before any 1.0.

What the library does not promise yet

This section exists because silence here reads as a promise. Not one of the following exists today:

  • the lifetime of a minor. How long 0.41 will receive fixes after 0.42 comes out is not declared;
  • a deprecation period. A subpath may disappear in the same release in which its replacement appears: that is what happened with GrCodeBlock;
  • backports of security fixes into previous minors;
  • since and deprecated metadata on components. A component page does not say which version a prop appeared in: the library does not carry that data yet, and the portal will not invent it.

What to do instead:

  1. Pin the minor. On 0.x that happens by itself — see the callout above — but check that package.json holds a range rather than latest.
  2. Read the changelog of the package you are raising. Not a shared one: every package has its own, and a breaking change is described there with a diff.
  3. Raise them one at a time. A companion and the core are tied by a range rather than by a shared version: updating the core does not require updating the companions as long as the range still holds.

Where to see the changes

The changelogs on this portal are assembled from the changelogs of the packages in the library repository — one per package, with diffs and explanations. It is the same text as in the repository: the portal does not retell it.

Last reviewed: 2026-09-02