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.
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/tokensseparately 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
- Estimate component count for the year (10 / 30 / 100+).
- Are there multiple consumer apps in the same org?
- Do you need independent package publishing?
- 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.