AI for Designers (UX, Product, Brand)
Proficient · M4 · lesson 4 of 27 · queued
Preview — browse every lesson free. Enroll to mark lessons complete, open partner links and save your progress. Login & enroll →
Component Library Deprecation Lifecycle: Signaling, Migration Prompts, and Telemetry
📖
now learning

Component Library Deprecation Lifecycle: Signaling, Migration Prompts, and Telemetry

15 min

Building a component is the easy half of a component's life. The hard half is retiring one, because a component never dies when you decide it should - it dies when the last app that consumes it stops, and most teams have no idea which apps those are. The previous lesson taught you to document a component so an AI agent reads its intended use; this lesson teaches you to document a component's end of life so the same agent, and every human consumer, knows it is on the way out and what to use instead. You will design a real deprecation lifecycle: a @deprecated flag that lives in both the token and the MDX layer, a migration-prompt pattern an agent surfaces to consumers ("this component is deprecated; the replacement is X, with these prop changes"), and lifecycle telemetry that answers the question every deprecation actually turns on - who still uses this, and where. The artifact is a deprecation playbook plus one component you actually deprecate, with telemetry attached, so the playbook is proven rather than theoretical.

Why Deprecation Is the Hardest Part of a Design System

Adding a component is an act of pure creation: you make a thing, document it, and consumers adopt it on their own schedule. Nobody is harmed by a new component sitting unused. Deprecation is the opposite - it is an act of removal that depends entirely on the cooperation of people who did not ask to be disrupted. The old LegacyCard works fine for the eight teams shipping on it. Their feature works, their tests pass, and the day you decide LegacyCard is deprecated, nothing changes for them unless you make it change, and even then they have every incentive to ignore you because migrating costs them time they would rather spend on their own roadmap. This is why design-system components accumulate like sediment: deprecating is everyone's responsibility and no one's priority, so the old component lives on for years past its replacement, doubling the surface the system has to maintain and the surface an AI agent has to read.

The failure has a specific shape, and naming it sharpens the fix. A deprecation that exists only in a designer's head, or only in a Slack announcement, is not a deprecation - it is a wish. The teams on LegacyCard did not see your Slack message, or saw it and forgot, and the component carries no signal that it is dying, so a new engineer joining one of those teams will look at LegacyCard, see a working component in the library, and reasonably build new features on it, deepening the exact dependency you were trying to drain. Worse, an AI agent connected to your system reads LegacyCard as a perfectly good component - it is in the library, it has props, it renders - and will happily generate new code using it, because nothing in what the agent can read says "do not use this for new work." A deprecation that is not written into the artifacts consumers and agents actually read does not exist. The entire job of a deprecation lifecycle is to make the dying state legible, in the places the readers look, so that the signal reaches the people and the agents who would otherwise extend the dependency.

The Three Layers Where the Signal Has to Live

A deprecation signal has to live wherever a consumer might decide to use the component, because a signal in one place and not another just routes consumers around it. There are three layers that matter, and a real deprecation writes the signal into all three.

The Token and Metadata Layer

The structural layer is where the deprecation becomes machine-readable in a way tools can act on automatically. In a DTCG token file, this is the $deprecated field (or a $extensions entry carrying deprecation metadata) on a token that a dying component depends on; in a component's own metadata, it is a @deprecated annotation in the source - the JSDoc @deprecated tag most editors and type systems already understand. The value of putting it here is that it is enforceable: a linter can flag any code that imports a deprecated component, a CI check can fail a build that adds a new usage, and an editor can strike through the component name when an engineer types it. This is the layer that turns deprecation from a request into a constraint, because tooling reads it without anyone having to remember to look. The structural flag is also what an MCP-enabled agent reads as a hard signal: a component carrying @deprecated in its metadata is a component the agent can be told to never recommend for new work.

The MDX Documentation Layer

The structural flag says that the component is deprecated; the documentation layer says what to do about it. This is where the previous lesson's MDX blocks earn a second use. The Meta and Description of a deprecated component must change from describing current usage to redirecting away from it: "Deprecated as of the March release. Use Card instead; this component will be removed after the September release." The Description stops carrying usage rules and starts carrying migration guidance - the prop mapping, the behavior differences, the gotchas of moving. This matters because a consumer or an agent that reads the documentation to learn how to use the component must instead learn how to leave it, and if the documentation still reads like current usage instructions, both the human and the agent will treat the deprecated component as a live one. A deprecated component whose documentation still teaches its usage is documentation fighting the deprecation.

The Runtime and Human Layer

The third layer is the one consumers cannot route around: a runtime signal and a human announcement. A console warning when the deprecated component mounts in development ("LegacyCard is deprecated; migrate to Card before September") reaches the engineer who never read the docs and never saw the Slack message, at the moment they run the code. The human layer - a changelog entry, a design-system release note, a direct message to the teams telemetry shows are still consuming it - reaches the people who make the migration decision. None of these three layers is sufficient alone: the structural flag without documentation tells consumers to stop without telling them where to go; the documentation without the runtime warning is invisible to anyone who does not read it; the human announcement without the structural flag is a wish again. The deprecation is real only when all three carry the signal.

A deprecation that lives only in your head, or only in a Slack message, is a wish. It becomes real only when the dying state is written into the artifacts consumers and agents actually read - the structural flag, the documentation, and the runtime warning - so the signal reaches the reader at the moment they would otherwise extend the dependency.

The Migration-Prompt Pattern: Turning the Agent Into a Migration Ally

Here is where the AI-integrated version of this work pays off in a way the old manual version never could. In a system an agent reads, a deprecation is not just a constraint on the agent ("do not use the deprecated component") - it is a capability you can hand the agent ("when you encounter the deprecated component, suggest the replacement"). The migration-prompt pattern is documentation written specifically so that an agent surfaces it to consumers as a migration suggestion. You write, in the deprecated component's metadata and MDX, a structured migration note: the replacement component, the prop-by-prop mapping, and the behavior differences. "Replaced by Card. LegacyCard's title prop maps to Card's heading; the bordered boolean becomes variant=outlined; LegacyCard defaulted to a shadow and Card does not, so add elevation=1 to preserve the look."

Now an agent reading the system - generating a new screen, or reviewing existing code, or answering a developer who asks how to build a card - encounters the deprecation and the migration note together and can act on both. Asked to build a card, it uses Card, not LegacyCard, because the deprecation flag steered it away. Asked to update a file that uses LegacyCard, it can propose the migration: swap the component, remap the props per the documented mapping, add the elevation to preserve the look. The migration that used to be a tedious manual find-and-update across eight teams becomes something an agent can draft, with a human reviewing each change. This is the leverage: you write the migration mapping once, into the place the agent reads, and the agent applies it across every consumer instead of you chasing each team. The migration-prompt pattern is how a deprecation stops being a thing you announce and starts being a thing the system helps execute.

The discipline here is the same division of labor that runs through the whole chapter. You author the migration mapping, because only you know that Card dropped the default shadow and that consumers will need the elevation to avoid a visual regression - that is design judgment about what "preserve the look" means, and the agent cannot infer it. The agent applies the mapping mechanically across consumers, which is the tedious part you do badly and it does well. A migration mapping the agent invents on its own is a guess; a migration mapping you author and the agent applies is a leverage-positive collaboration. Write the judgment, let the agent do the labor.

Lifecycle Telemetry: Who Still Uses This, and Where

Every deprecation decision turns on one question that most teams answer with a guess: who still consumes the dying component, and in what contexts? Without an answer, deprecation is flying blind. You cannot set a sane removal date, because you do not know whether two teams or twenty are still on it. You cannot prioritize the migration, because you do not know which usages are high-traffic production surfaces and which are a forgotten internal tool. You cannot even tell whether your deprecation announcement worked, because you have no before-and-after count of consumers. Lifecycle telemetry is the instrumentation that turns these guesses into facts, and it is the difference between a deprecation you manage and a deprecation you hope about.

The telemetry has two halves. The static half is a codebase scan - which is the drift-detection capability of the next lesson, applied to a single component: an agent or a search tool scans every repo that consumes the design system and counts the import sites of the deprecated component, by repo, by file, by team. This tells you the static footprint: LegacyCard is imported in 47 files across 6 repos owned by 4 teams. The dynamic half is runtime instrumentation: the deprecated component, when it mounts, emits a lightweight telemetry event - which app, which route, how often - so you learn not just that LegacyCard is imported but that it actually renders 30,000 times a day on the billing dashboard and twice a month on a deprecated admin page. The static scan tells you the migration cost (47 files to change); the runtime telemetry tells you the migration priority (the billing dashboard first, the admin page whenever).

This data is what makes the rest of the lifecycle defensible. The removal date is set from the telemetry - you do not remove the component until the consumer count reaches zero, and the telemetry tells you when that is, rather than you guessing and breaking someone's production build. The migration sequence is set from the telemetry - high-traffic consumers first, because that is where the risk and the value concentrate. And the deprecation's success is measured from the telemetry - a healthy deprecation shows the consumer count declining release over release, and a stalled one shows it flat, which is the signal to escalate (a direct message to the holdout teams, an offer to pair on the migration, or a hard removal date with engineering-leadership backing). Telemetry turns deprecation from an announcement into a managed decline with a measurable trajectory.

The Deprecation Playbook: Making It Repeatable, Not Heroic

The first deprecation you run this way is a project. The tenth should be a checklist, because a deprecation lifecycle that depends on you personally remembering all the steps is a lifecycle that breaks the moment you are on vacation or someone else owns the system. The playbook is the artifact that turns the lifecycle from a heroic one-off into a repeatable process, and it is half of what you ship from this lesson. A good deprecation playbook is short and sequenced: it states the steps in the order they happen, names the owner of each, and gives the criteria for advancing from one stage to the next.

The stages it should encode, roughly: propose (a deprecation is proposed with a named replacement and a reason - you do not deprecate without somewhere for consumers to go); flag (write the @deprecated annotation into the metadata, the migration note into the MDX, and the console warning into the runtime, so all three layers carry the signal); announce (changelog, release note, and direct outreach to the teams telemetry shows are consuming it); measure (stand up the static scan and runtime telemetry so you have a baseline consumer count); migrate (work the consumers down, high-traffic first, with agent-drafted migrations and human review); monitor (watch the consumer count decline release over release, escalate if it stalls); and remove (delete the component only when telemetry shows the consumer count has reached zero, never before). Each stage has an owner and an advancement criterion, so the deprecation moves through the pipeline on rules rather than on someone's memory.

The playbook is also where you encode the policies that prevent the common failures: never deprecate without a replacement, never set a removal date before telemetry, never remove a component with live consumers, and always write the migration mapping for the agent rather than expecting consumers to figure out the move themselves. These are the rules a mature design-system team learns through painful experience - a removal that broke a production build, a deprecation announcement nobody acted on because there was nowhere to go - and the playbook is where you write them down so the team does not have to relearn them each time. A deprecation playbook is the institutional memory of how your team retires components, made explicit so it survives turnover and scales past your personal involvement.

Shipping One Real Deprecation, With Telemetry Attached

A playbook nobody has run is a theory, so the second half of the artifact is one actual deprecation, executed end to end, with the telemetry attached as proof. Pick a real component your system should retire - one with a clear replacement, because the whole lifecycle depends on having somewhere to send consumers. Run it through the playbook: flag it in all three layers, write the migration mapping, announce it, and crucially, stand up the telemetry so you have a real consumer count and not a guess. The telemetry attached to this one deprecation is what makes the artifact reviewable - a manager or peer can look at it and see not just that you announced a deprecation but that you know exactly who is affected, where, and how the migration is progressing.

What you will likely learn from the telemetry is itself the lesson's payoff: the consumer count is almost always different from what the team assumed. The component everyone thought was barely used turns out to render half a million times a day on a surface nobody remembered; the component someone was sure three teams depended on turns out to have one real consumer and five that imported it and never shipped. These surprises are exactly why telemetry matters - the assumptions a team carries about its own component usage are frequently wrong, and a deprecation run on wrong assumptions either breaks production (removing something more used than you thought) or wastes months chasing migrations that did not matter (over-prioritizing something barely used). The telemetry replaces the assumption with the fact, and the fact is what lets you run the deprecation safely and in the right order.

Step back and see what this artifact is. You took the most neglected, sediment-accumulating part of a design system - retiring components - and turned it into an instrumented, agent-assisted, repeatable process. The deprecation is legible in every layer a consumer or agent reads, the migration is something the agent helps execute rather than something you chase by hand, and the decisions are driven by telemetry rather than guesses. That is senior systems work: not the heroics of personally migrating eight teams, but the leverage of building a lifecycle that migrates them with a fraction of the effort, measures itself, and runs the same way the next ten times. It is the same move as the tokens and the documentation before it - taking something that lived in judgment and manual effort and turning it into infrastructure that does the work itself.

Key Takeaways

  • Deprecation is the hardest part of a design system because it depends on the cooperation of consumers who did not ask to be disrupted. A deprecation that lives only in your head or a Slack message is a wish; components accumulate like sediment because deprecating is everyone's responsibility and no one's priority.
  • The deprecation signal must live in three layers: the structural flag (@deprecated annotation and DTCG $deprecated/$extensions metadata, which tooling and agents read as a hard constraint), the MDX documentation (which switches from teaching usage to redirecting away, carrying the migration mapping), and the runtime/human layer (a console warning and direct outreach). None is sufficient alone.
  • The migration-prompt pattern turns the agent into a migration ally: you author a structured migration note (replacement component, prop-by-prop mapping, behavior differences) into the place the agent reads, and the agent both avoids the deprecated component for new work and drafts the migration across consumers - you write the judgment, the agent does the labor.
  • Lifecycle telemetry answers the question every deprecation turns on - who still consumes this, and where. The static half is a codebase scan counting import sites by repo and team; the dynamic half is runtime instrumentation counting actual renders by app and route. The scan gives migration cost; the telemetry gives migration priority.
  • Telemetry makes the lifecycle defensible: the removal date is set when the consumer count reaches zero (never before), the migration sequence runs high-traffic first, and success is measured by the consumer count declining release over release - a flat count is the signal to escalate.
  • Ship two artifacts: a sequenced deprecation playbook (propose, flag, announce, measure, migrate, monitor, remove - each with an owner and an advancement criterion) that makes the lifecycle repeatable rather than heroic, and one real deprecation run end to end with telemetry attached, which almost always reveals the team's assumptions about its own usage were wrong.