Before removing design tokens that look unused, how would you audit usage across web, native mobile and design-file consumers, and why can zero search hits mislead?
answer
- who consumes the package at all
- search the output name, not source
- names assembled at runtime
- tokens that alias other tokens
- deprecate first, then wait
basics
~20 sScan every known consumer for each token's per-platform output name, check which tokens other tokens alias, and deprecate candidates for a release before deleting them. Zero hits mislead because names get transformed, assembled dynamically or used by consumers you never scanned.
solid answer
~50 sStart with the **consumer list**: every web codebase, native app and design library that installs the package. For each token, search for its **per-platform output name**, not the source name, because outputs are cased and prefixed differently per platform. Walk the **token graph** too: a token no product references may still be aliased by another token, and removing it breaks the set itself. Zero hits mislead when names are **assembled at runtime** from a status and a suffix, when a consumer is **pinned to an older version** or simply unknown, or when usage lives in design files that plain text search cannot see. So treat a zero as a candidate, not a verdict: mark it `$deprecated` with an explanation, ship that as a minor so any unseen consumer gets a warning, re-scan after a release cycle, and remove it in the next major.
go deeper
Recall that removing a token breaks anyone still using it, so you check usage everywhere before deleting and deprecate first.
Explain why searching for the source name misses per-platform output names, dynamically assembled names and internal aliases between tokens.
Lay out an audit across web, native and design consumers that ends in a deprecation release, a re-scan and a removal in the next major, and explain how it protects consumers you never found.
Weigh the cost of carrying unused tokens against the cost of audits and majors, and decide how often pruning is worth a breaking release.
## Why prune tokens at all Every token a design system publishes is a promise to support it. Unused tokens are not free: - They crowd the documentation and the design library, so a designer choosing a color for a new vaccination-reminder banner has more wrong options to pick from. - Every palette or scale change has to decide what to do with them. - They make every platform's output larger and every audit slower. But removing a token is a **breaking change** for anyone who still uses it, so the audit has to be trustworthy before anything is deleted. ## Where references hide | Consumer | What to search for | Why a naive search misses it | |---|---|---| | Web codebases | The web output name of each token | Output names are cased and prefixed differently from the source name | | Native mobile apps | The generated constant or resource name | A different casing again, and sometimes grouped under a type | | Design libraries | Styles and variables bound in design files | Bindings are not plain text; they need the library's own usage report | | The token set itself | Brace references to the token | Usage by another token never appears in any product codebase | | Emails, printed forms, partner widgets | Whatever format they were generated in | Often outside the repositories anyone scans | In a veterinary booking system, a token that no app mentions might still colour the appointment reminder email, sit behind a semantic token the kiosk uses, or be bound in the design file for the new clinic onboarding flow. ## Why zero hits can mislead - **Transformed names.** The source says `status.urgent.surface`; the web output and the native output each spell it differently, so searching the source spelling finds nothing. - **Dynamically assembled names.** Code that builds a name from a variable, such as the appointment status plus a fixed suffix, never contains any full token name. Search for the partial patterns too. - **Internal aliases.** If a semantic token references the candidate, the candidate is used by everyone who uses that semantic token. The token format requires tools to report an unresolvable reference as an error, so deleting it breaks the token build — or, with a less strict tool, the outputs. - **Consumers you did not scan** — a team pinned to an older major, a repository created last month, a partner clinic's embedded booking widget. - **Design-only usage** that will reach code at the next handoff. ## An audit process that holds up 1. **Build the consumer list** from whatever records who installs the package, and keep it current. 2. **Compute every output name** of each token for each platform, using the same rules the token build uses. 3. **Scan all known consumers** for full names and for partial patterns that suggest dynamic assembly. 4. **Walk inbound aliases** in the token graph; a token with inbound references is used, full stop. 5. **Collect design-library usage** from the design tool's own reporting. 6. **Deprecate the candidates** with `$deprecated` and a string such as that the token is unused and will be removed in the next major, and ship it as a minor. Any consumer the scan missed now sees a warning instead of a broken screen. 7. **Re-scan after at least one release cycle**, then remove the survivors in the next major release with the removed names listed in the release notes. ## A related signal worth separating An audit often also finds **hardcoded values** that equal a token's value — a raw hex code for the open-slot green in the staff dashboard. That is not evidence the token is unused; it is evidence a consumer bypassed it, often because the token was hard to find. Track it as an adoption problem, and do not let it change the removal decision.
- Why is deprecating an apparently unused token before deleting it worth a whole release cycle?The scan only covers consumers you know about and patterns you thought to search. A deprecation release turns any consumer you missed into one that receives a warning naming the change, rather than one whose screen breaks. Removing in a later major then costs nobody a surprise, and the warning period doubles as a final check of the audit.
- How do you catch token names that are assembled at runtime rather than written out in full?Search for the fixed fragments that such code must contain — a prefix or a suffix shared by a token family — and review each hit. Treat any token family that is accessed dynamically as used as a whole unless the code shows which members it can produce, and prefer mapping tables that spell full names so future audits can see them.
saying these in an interview costs you the question
- A text search for the source token name across our main repository is enough.
- A token that no product code references can be deleted in a patch release.
- Tokens referenced only by other tokens are safe to remove because no app uses them.
- If designers stopped using a token, engineers must have stopped too.
- Hardcoded copies of a token's value prove the token itself is unused.