Project structure

Repository structure decides how easy it is to find components, publish packages, onboard people, and scale the system. A bad structure does not “break” a button today — it slows every release after that.

What structure should enable

  • Maintainability — clear where to change tokens, components, and docs.
  • Scalability — you can add the 50th component without chaos.
  • Collaboration — designers and engineers look at the same artifacts.
  • Discoverability — predictable names and hierarchy.
  • Build performance — sensible package splits and build caching.

Monorepo vs multi-repo

Monorepo

One repository: tokens, components, docs, sometimes consumer apps.

Pros: single source of truth, atomic changes across “token + component + docs,” easier version sync. Cons: heavier tooling (pnpm/npm workspaces, Turborepo/Nx), needs ownership discipline.

Multi-repo

Separate repositories for the library, documentation, and apps.

Pros: independent access control and releases. Cons: version hell, harder to sync tokens and consumers, higher CI overhead.

Important

For most product teams, a monorepo with packages tokens, components, docs is better. Multi-repo is justified with strict org boundaries or a dedicated platform team with its own release train.

Core design-system packages

packages/
  tokens/        # colors, typography, spacing, breakpoints
  components/    # UI components built on tokens
  utils/         # cn/helpers, sometimes icons
apps/
  storybook/     # component showcase and docs
  docs/          # optional guidelines site

That split lets you:

  • change the palette without rewriting every component by hand;
  • publish @scope/tokens separately from the React layer;
  • keep Storybook as an app, not as “a folder inside a button.”

Code organization options

Flat (small DS)

All components in one file list. Fine for a prototype and <10 components. Scales poorly.

Feature-based (one folder per component)

components/button/
  Button.tsx
  Button.test.tsx
  Button.stories.tsx
  index.ts

Convenient for a mid-size library: code, tests, and stories live together.

Layered packages (recommended growth path)

Separate packages for tokens/components/icons + apps for Storybook/demo. Fits when you need independent publishing and multiple consumers.

Practical starter skeleton for the course

design-system/
  src/
    components/
      ui/
      layout/
      feedback/
    tokens/
      colors.js
      typography.js
      spacing.js
      index.js
    utils/
    styles/
      tokens.css
      globals.css
    index.js
  .storybook/
  package.json
  vite.config.js

Early on you can keep tokens and components in one package, but logically split folders as if they were future packages. Migrating to a monorepo then becomes almost mechanical.

Naming and ownership boundaries

  • Tokens know nothing about React.
  • Components do not hardcode #3B82F6 — they read tokens.
  • Utils do not pull in UI.
  • Storybook does not become a dump of product business logic.

Example public API:

// src/index.js
export * from './components';
export * from './tokens';
export * from './utils';

How to choose structure in an hour

  1. Estimate component count for the year (10 / 30 / 100+).
  2. Are there multiple consumer apps in the same org?
  3. Do you need independent package publishing?
  4. What is the team size, and who owns the DS?

If the team is small — feature-based single package. If multiple products and a dedicated DS team — monorepo + packages/tokens + packages/components + apps/storybook.

Structure is part of the design system too: it encodes how the team thinks about product layers.