[Context in your words: the projects, the team, and what was slowing delivery.] The fix was boring, well-understood structure, applied the same way in every project.
The layers
#Feature-Sliced Design splits a front-end into layers by responsibility. One rule does most of the work: a layer can only import from the layers below it, and slices on the same layer never import each other.
| Layer | Owns | Can import |
|---|---|---|
app | Providers, routing, global styles | all layers below |
pages | Route-level composition | widgets and below |
widgets | Large self-contained UI blocks | features and below |
features | User actions with business value | entities, shared |
entities | Business objects such as user, invoice, order | shared |
shared | UI kit, API client, utils, config | nothing |
Monorepo structure
#Each app keeps its own layers. Anything shared, like the design system, the generated API clients and the tooling, lives in packages.
.
├── apps/
│ ├── web/src/
│ │ ├── app/
│ │ ├── pages/
│ │ ├── widgets/
│ │ ├── features/
│ │ ├── entities/
│ │ └── shared/
│ └── admin/ # same layers
└── packages/
├── ui/ # design system and tokens
├── api/ # generated API clients
└── config/ # eslint, tsconfigPublic APIs, not deep imports
#Every slice exposes a single index.ts. Everything else stays private, which is what makes refactoring safe.
export { InvoiceCard } from "./ui/InvoiceCard";
export { useInvoice } from "./model/useInvoice";
export type { Invoice } from "./model/types";// avoid: reaches into the sliceimport { useInvoice } from "@/entities/invoice/model/useInvoice";// prefer: the public APIimport { useInvoice } from "@/entities/invoice";A TypeScript API generator
#Hand-written API clients drift from the backend. Generating typed clients removed the manual inconsistencies and turned most integration bugs into compile errors. [Name the tool and how it runs in CI.]
$ pnpm --filter @[org]/api generateBoring architecture wins.
P/02, How I work
What it changed
#- 5xlower infrastructure cost
- 90%fewer API integration bugs
- 50%less dev effort per project
The 50% came from SaaS boilerplate templates and a Figma-to-token pipeline. New projects start from a working base instead of an empty repo. [Add before and after kickoff times.]
Trade-offs
#[What it cost: the learning curve, the migration effort, and when you would skip it.]