CategoryProduct design

Own design system or library: who pays maintenance

9 min read

A design system you build and a component library you adopt solve the same problem. The difference is who pays to maintain them and who decides when something changes. Adoption rents that decision from a vendor. Building buys it and pays later. Choose by asking which bill your team can carry in year three.

What changes between building and adopting

Adopting a library means buying decisions someone already made. Spacing, focus states, keyboard behavior and the accessibility work behind a select or a dialog arrive finished. The cost is a dependency. The library decides what a component does, and you decide how it looks.

Building flips that around. You own the behavior, the tokens and the release cadence. You also own the bug in the dropdown, the migration for a renamed prop, and the review that keeps a raw hex value out of a button. The tokens and theme guide covers what owning that layer means in practice.

The work that disappears when you adopt is the work that is invisible when you build. The work that appears when you adopt is invisible until the vendor changes course.

Who pays for maintenance on each path

Adoption spreads maintenance across every team that uses the library. A security fix, a browser quirk or a new ARIA pattern lands once and everyone inherits it. The catch is that nobody inside your company is accountable for the schedule.

Material Components for the web, Google’s implementation of Material Design, shows what a vendor schedule looks like from the outside. Its README states that the project is no longer actively maintained and that updates will be turned off in the future. The same README says the library releases breaking changes about once a month while following semver, on a two-week cadence with one major release per month. A team that adopted it early paid nothing for years and now owns a migration with no upstream.

Building concentrates maintenance in one team. That team answers the questions, ships the fixes and carries the on-call for the components. Nielsen Norman Group names the cost directly in Design Systems 101. Creating and maintaining a design system is time-intensive and requires a dedicated team. The article adds that a design system isn’t a one-and-done solution, because it keeps evolving as teams send feedback.

Neither path removes the work. Adoption converts a fixed internal cost into a variable external one.

Who controls the decision to change

This is what decides most cases, and it has nothing to do with cost.

With an adopted library, the change decision belongs to people who don’t know your product. They read their own roadmap, their own design language and their own browser support matrix. Your feature request becomes one issue in a public backlog.

The pattern shows up in versioning. Radix Primitives publishes a dated changelog per component, and its release notes mark entries as breaking when a change requires action from callers. One early entry marks Accordion as a major release because the API renamed Accordion.Button to Accordion.Trigger and Accordion.Panel to Accordion.Content. Nobody using that component chose that date.

With a system you build, the decision belongs to a team inside the company. That team can move faster on your requirement and slower on everything else, because the same people who decide also implement.

Control is worth paying for only when your requirements differ from the mainstream. If your product needs what everyone needs, the vendor’s decision is usually better than yours.

What an exception costs

Every design system gets overridden. The question is the price of the override and who pays it.

In an adopted library, an exception is local and cheap at first. A wrapper component, an override stylesheet, a selector with higher specificity. The cost appears later, when the library changes the markup and the override breaks in a way that no test covers.

In a system you build, an exception is expensive at first and cheap later. Someone has to decide, name the new variant and ship it to every caller. After that, the exception is a documented part of the system, and the next team inherits it.

The asymmetry matters. An adopted library makes the first exception free and the hundredth expensive. A built system makes the first exception expensive and the hundredth cheap.

When the requirement doesn’t fit someone else’s component

This is the moment the decision gets tested, and it arrives on a schedule nobody controls.

The requirement usually fails to fit in one of four ways. The component lacks a state your product needs. The visual language diverges from the vendor’s design language. The behavior conflicts with a regulation or a platform convention in your market. Or the component is fine, and the version you need was deprecated before your release.

Material Components for the web is the clean version of the last case. A team that built on it in 2019 owns working code and no path forward, unless it forks. A fork means the maintenance that was outsourced comes back, with interest, to a team that no longer has the original context.

Radix takes the opposite position for the same problem. Its primitives ship behavior and leave styling to the caller, so a design divergence isn’t a fork. It is the intended use.

The failure mode to avoid is neither. It is adopting a styled library for the behavior, then fighting its styles for two years instead of forking or switching.

The middle path: headless library with your own style layer

Build or adopt doesn’t cover the whole choice. There is a middle path, which carries the behavior of an adopted library and the decisions of a built system.

A headless library ships the hard parts. Focus management, keyboard navigation, ARIA wiring, positioning and portal behavior arrive tested. You keep the tokens, the visual layer of the components and the design language. Radix Primitives keeps a public per-component version history for the behavior it does own.

The split reflects who is good at what. Accessibility and interaction details are expensive to get right and broadly shared. Visual language is specific to a product and cheap to change when you own the tokens.

The cost is real. You now maintain a styling layer that sits between the primitives and the screens. That layer needs owners, tests and a deprecation policy, exactly like a built system. The saving is that you never own the focus trap.

Headless is the right default for a product with a distinct visual identity and a small platform team. It is the wrong choice for a team with no capacity to maintain a layer, and for a product that is happy with the vendor’s design language.

When the ready library is the right call

Adoption wins more often than design system advocates admit.

Adopt when the product has one team, a short lifecycle, or a visual language that already matches a mature library. Adopt when the team can’t name an owner for maintenance in the next twelve months. Adopt when the platform surface is small and the accessibility work is the main risk.

The strongest case for adoption is a product that needs what everyone needs. A dashboard, an internal tool and a checkout flow solve problems that thousands of teams already solved, and the vendor absorbed that cost.

When building your own is waste

A design system is a bet on reuse. When reuse isn’t there, the maintenance has nothing to pay for it.

Building is waste when the product ships one interface and has no second consumer. It is waste when the same team would own both the system and the product, because the system then competes with the roadmap. It is waste when the visual language still changes every quarter, since the tokens will be rewritten before they are reused.

NN/g lists the same conditions from the other side. A design system needs a dedicated team, needs time to teach, and fights the perception that projects are one-off creations.

Where the sources disagree

The three NN/g articles don’t describe the same system, and the difference is worth naming before you budget for one.

Design Systems 101 treats a dedicated team as a prerequisite and as the cost of entry. Lean design system teams reports the opposite shape in practice. Teams of two to five people are the norm, and the small size is what makes them effective, not a compromise. Design system maturity adds the part planning usually misses. Maturity isn’t linear, and systems regress after they launch.

The three agree on two points, and those are the ones to keep. The system needs a named owner, and it keeps changing after launch. Consistency and standards is the reason the owner has a job at all: consistency is a property someone maintains, not a state a system reaches.

Size the team from your own evidence, not from the prerequisite. If two to five people can carry it, the case for building gets better, not worse.

The signal to start building is specific. A second team appears, or the same screen pattern gets rebuilt for the third time. Both mean someone is already paying for the duplication.

How to decide, and what to measure

Decide with three questions, answered before any code is written.

  • Who answers when the component needs a change, and how long that takes today.
  • What one exception costs in hours, in each option, and who approves it.
  • What happens to this product in three years if the library stops shipping or the requirement moves.

After the decision, track those three numbers, and not the size of the component library.

  • Time from request to a changed component, counted from the first message to the shipped release.
  • Number of local overrides against system components, counted per team and reviewed on a schedule.
  • Upgrade cost per major version, in hours, including the parts that broke silently.

Two more help on the maintenance side. The share of components with a named owner in the repository, and the age of the oldest unresolved request.

Measure per team, never as an average. One strong adopter can carry a number that hides three teams building around the system.

Check before you sign off

  • Confirm the change decision has a named owner, in both paths.
  • Confirm the exit cost is written down before adoption, including a fork scenario.
  • Confirm each exception has a recorded reason and an end condition.
  • Confirm the styling layer has a deprecation policy if you chose headless.
  • Confirm the three metrics have a reader who acts on them.

Build or adopt matters less than three things: a named owner for the change decision, a measured cost for the exception, and a plan for the year the library or the product moves.

Sources

More articles

See all articles