Reading the numbers
Almost every number in the dashboard counts one of two things: components or occurrences. This page explains the choices behind those counts, so you know what a number can and can't tell you. For where each number sits on screen, see Repos, Find where a component is used, Packages, Charts and Migrations and retirements.
Every number starts from each repo's latest scan
The dashboard keeps each repo's history of scans, but most pages read only each repo's latest scan, and numbers across repos add those latest scans together. A repo last scanned three months ago still counts, as it looked three months ago.
Latest means the scan of the newest commit: the dashboard dates each scan by its commit's date. The time of upload doesn't matter: uploading a scan of an older commit adds it to the repo's history without becoming its latest scan. The CLI uploads only commits on the branch the dashboard tracks, so a scan of a feature branch never becomes the repo's latest. A commit dated after its scan reached the dashboard, for example one made on a computer whose clock runs fast, is placed in the repo's history by when its scan arrived instead.
When a repo's latest scan isn't ready, its numbers come from its newest scan that is, and the page says so. A repo with no ready scan is left out of the totals until one is ready, and the page names it. See When a page shows Preparing scan data.
Two places read more than the latest scan:
- A repo page opened on an older scan shows that scan.
- Charts over time, including the charts on a repo page's Adoption tab, read the whole history. Each point in time uses every repo's most recent ready scan as of that moment.
Components, occurrences and files
These three counts answer different questions about the same code:
- A component is one distinct thing that gets used, such as
Buttonfrom@acme/ui. - An occurrence is one place in the code that uses it.
- Files counts the files that hold at least one occurrence.
If storefront uses Button in 40 places across 12 files, that is 1 component, 40 occurrences and 12 files.
Most tables sort by occurrences and every chart counts them, because a component used 500 times matters more to a migration than one used twice. Component counts tell you how far a library reaches. File counts tell you how spread out the work of changing a component would be.
Only occurrences the scan tied to a component are counted. Unresolved occurrences stay in the scan's JSON, but the dashboard leaves them out of every number.
Tables list every component the scan recorded, including ones with no occurrences, such as a page component that only your router loads, so you can find them. A repo's Components count includes them. A package's component count leaves them out, so a package page's Components table can have more rows than its header's count.
Which components add up across repos
Whether a component counts once across all your repos, or once per repo, depends on its kind, as How components are found explains:
- A component from a package, or a web component, is the same component in every repo.
Buttonfrom@acme/uiused instorefrontandcheckoutcounts as one component across both, and so does<acme-button>. - A component defined in the repo belongs to that repo. A
Cardinstorefrontand aCardincheckoutare separate code, even when their files look alike, so they count as two.
Versions
The version shown for a package is the one installed in the repo when the scan ran, not the version range your package.json asks for. Components defined in the repo, and web components that belong to no package, have no version and show as unversioned.
The version bar on a package page and on a component's page across repos splits occurrences by version. It colours the highest version found in your scans and greys out the rest, so the grey share is the code still on an older version.
The dashboard doesn't check what is published on npm, so "highest" can be behind the newest release. If every repo is on 4.2.0 and 5.0.0 is out, 4.2.0 still takes the colour.
Where "deprecated" comes from
A component is deprecated in the dashboard only when a lifecycle record marks it superseded or retired: a record on the component itself, on the component it is part of (a record on Card covers Card.Header), or on its whole package.
Only components imported from a package, and web components the scan links to a package, can be deprecated. A component defined in the repo never is, even when it lives in a workspace package that a record names: a record on @acme/ui covers Button in the repos that install @acme/ui, but not in the monorepo where @acme/ui is written.
Deprecation is a decision your team records once, on the governance page, rather than something each scan reports. That has two effects:
- A record applies to every repo at once, and to every scan already uploaded. No rescan is needed, and a migration chart can show the full history from the first scan that used the deprecated component.
- Nothing in your code or your packages marks a component deprecated, not even a
@deprecatedcomment. Every deprecated mark in the dashboard traces back to one list you can read and edit.
Deprecated counts differ by page. A repo page counts each deprecated component once. The packages list and a package page add up across repos, so a deprecated component used in three repos counts three times, and the number falls as each repo moves off it. A component's page across repos says how many repos it is deprecated in.
How a migration's progress is counted
A superseded record names a deprecated side and a successor, each a component or a whole package. A side that names a component counts it from every entry point, such as @acme/ui and @acme/ui/card, together with its parts, such as Card.Header for Card, unless a part has a record of its own. Progress reads N% migrated:
N% migrated = successor occurrences ÷ (deprecated-side occurrences + successor occurrences)
If checkout has 30 uses of LegacyButton and 90 of its successor Button, it reads 75% migrated.
The denominator is the pair, not every occurrence in the repo. A migration asks how much of the old one is left and how much of the new one has arrived, so the rest of the repo doesn't dilute it. A repo that also uses a charting library and a router shows the same progress as a repo that uses nothing else.
The successor side counts every use of the successor within the scope, including uses that never replaced anything. On a repo's Adoption tab the scope is that repo; on the charts page it is every repo. If storefront uses Button 400 times and never used LegacyButton, the charts page reads 94.2% migrated (490 ÷ 520), while checkout's Adoption tab still reads 75%.
If no scan within the scope has the successor component yet, the successor side counts every component of its package instead, and the row names the package rather than the component.
A retirement has no successor, so there is nothing to divide. It reads N remaining, the occurrences still in use.
A record is complete when the deprecated side has no occurrences in any latest scan within the scope. So a migration can be complete on one repo's Adoption tab and still active on the charts page. A repo that never used LegacyButton has no row for it on its Adoption tab.
Why there is no single adoption percentage
The dashboard doesn't show one percentage for "how much of our code uses the design system". Such a number needs a denominator, and every candidate misleads. Divided by all occurrences, a repo that rightly uses other libraries reads as behind. Added up across repos, it blends teams with different needs into one figure that describes none of them.
Instead, each share has a denominator you chose:
- A migration's progress, measured against its own pair.
- A chart's share, measured against the series you put on it, such as your library tags and local.
Why shares can overlap
A chart's share divides each series by the total of every series on the same chart. So a share is always a share of something smaller than the whole codebase: a package that no series covers, such as a third-party router, is left out, and adding or removing a series changes every other series' share.
Each series counts its own occurrences without checking the others. When one component falls into two series, it counts in both. The shares still add up to 100%, but the parts are not separate slices of the code. That happens when:
- Two tags match the same package.
- A chart holds a tag and a package under it, or a package and a component from it.
- A component defined in the repo lives in a workspace package that a tag or a package series matches. It counts there and under local.
On a share chart, the chart builder warns that series can share components, unless every series is a different single component. Where series can overlap, read their shares as a comparison between series, not a breakdown of the code. For a clean breakdown, pick series that can't contain each other, such as library tags whose patterns match different packages. The warning still shows for those, because the dashboard doesn't compare tag patterns.