Skip to main content

Boundaries Between Feature, Shared, and Design System

What actually helps is being clear about what is feature-local code, what is shared, and what has become a stable contract.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

The problem

A lot of frontend structure becomes organizational theater.

You open the tree and see:

  • features/
  • shared/
  • design-system/

Everything looks serious.

But in real use:

  • shared receives anything nobody knows where to put
  • design-system becomes the home for product exceptions
  • one feature imports from another for convenience

In the end, the folders look better and the boundaries are still bad.

Mental model

Those names should not represent aesthetics.

They should represent different levels of contract.

A practical way to think about it:

  • feature = code that exists to solve one specific product flow or case
  • shared = reusable code across features, but not yet part of the central visual or system contract
  • design system = tokens, patterns, and components with a stable contract and clear consistency responsibility

Short version:

the question is not “which folder can hold this?” The question is “what is the real scope of this code, and how stable does it need to be?”

Breaking the boundaries down

What usually stays in feature

Feature is where code stays when it is still tightly tied to the context of that flow.

Examples:

  • checkout screen components
  • filter-combination rules for that listing
  • onboarding-specific copy
  • state and composition from that domain

Even if the code looks clean.

Even if it might become reusable in the future.

If its value still depends on that context, keeping it local is usually healthier.

What usually goes to shared

Shared is the middle ground.

It serves things that:

  • appear across several features
  • have cross-cutting utility
  • are still not part of the central UI contract

Examples:

  • date helpers
  • integration wrappers
  • small reusable screen blocks
  • cross-cutting hooks that do not belong to the design system

The risk here is turning shared into a dump.

If everything goes there, nothing has a clear owner.

What really deserves to be in the design system

The design system should carry what needs to be consistent, predictable, and stable.

Examples:

  • tokens
  • primitives
  • base form components
  • standardized visual feedback
  • recurring accessibility and interaction rules

The classic mistake is promoting a product exception too early.

When that happens, the design system becomes a catalog of special cases with infinite props.

Simple example

Imagine a status badge.

Scenario 1:

  • it only appears in one billing flow
  • it follows rules specific to that context
  • its meaning is still changing

That is probably feature.

Scenario 2:

  • it appears across several internal screens
  • it reuses simple behavior
  • it still does not define central product language

That may be shared.

Scenario 3:

  • it became a recurring visual pattern
  • it needs to follow tokens and accessibility consistently
  • it already has clear semantics and stable states

Now it starts to look like design system.

The test that usually helps

Before moving code, it helps to ask:

  1. is this specific to one flow?
  2. is this useful across several places without depending on the original domain?
  3. did this become a stable contract of interface and consistency?

Those answers usually point to a better home than any folder convention.

Common mistakes

  • Sending to shared everything that created local discomfort.
  • Pushing a premature component into the design system.
  • Creating boundaries by cargo cult, with no decision rule.
  • Letting one feature depend on another and calling that pragmatism.

How a senior thinks

People who look well at frontend architecture tend to be conservative about promoting code.

The healthy reasoning usually is:

  • keep it local first
  • then watch for real repetition
  • only then promote to shared
  • and only promote to design system when the contract is already stable

That avoids two bad costs:

  • abstraction too early
  • fake consistency based on an overly generic component

Interview angle

This topic shows up a lot in:

  • frontend architecture
  • system design focused on web product
  • large codebase review

Weak answer:

I would separate things into feature, shared, and design system.

Strong answer:

  • explains the promotion criteria
  • shows that stability matters
  • separates cross-cutting reuse from central contract

That is what communicates maturity.

Closing thought

Feature, shared, and design system only help when they represent real boundaries.

If they become only folder decoration, the team gets a prettier tree and an equally confusing codebase.

Good structure is not the one that looks organized. It is the one that makes clear what is still local, what already became cross-cutting utility, and what truly deserves a stable contract.

Quick summary

What to keep in your head

Practice checklist

Use this when you answer

Next article Product Events: How to Instrument Without Generating Analytics Garbage Previous article Design Systems in Practice: What to Standardize and What to Leave Flexible

Keep exploring

Related articles