Derived Modular Arch
Start

Project layout

The src/ tree, composition roots, and where to put code on different frameworks.

DMA isn't tied to one framework. The rules are the same; only the composition root folder name changes — where routes and layout mount modules.

Base tree

src/
├── app/         # composition root (Next.js App Router, Vite+React)
├── features/    # leaf modules
├── services/    # appears on promotion — don't create upfront
└── shared/
    ├── ui/
    ├── lib/
    ├── api/
    ├── model/
    └── domain/  # optional

Composition roots

Under src/, any of these folders is the same layer by DMA rules:

FolderTypical framework
app/Next.js App Router, Vite + React
pages/Astro, classic Next pages
routes/TanStack Router, SvelteKit

All of them:

  • mount modules through */public/*;
  • are not imported by modules;
  • keep routes thin — import from public/, minimal logic.
// src/app/checkout/page.tsx
import { CheckoutPage } from "@/features/checkout/public/checkout-page";

export default function Page() {
  return <CheckoutPage />;
}

If the project has multiple roots, prefer app/. Tooling picks app first on conflict.

Where to put what

You have…Put it in…
Route, layout, providersComposition root
Screen / user flowfeatures/<name>/public/ or stage-0 file
State for one featureInside the feature, next to the consumer
Logic needed by other modules (product)services/<name>/public/
Portable UI / helpersshared/ui/, shared/lib/
Base HTTP client, interceptorsshared/api/
Endpoints for one featureInside the feature (*.api.ts)
Wiring features / eventsComposition root — props, providers, ports
Unit testsNext to the file (*.test.ts)

Examples by framework

The DMA repo has five clean examples with one product story (catalog, checkout, cart):

ExampleComposition rootStack
vite-reactsrc/app/Vite + React
next-appsrc/app/Next.js
astro-pagessrc/pages/Astro
sveltekit-routessrc/routes/SvelteKit
vue-vitesrc/app/Vue 3 + Vite

Easiest to start with vite-react — runnable, with tests and the full module stage ladder.

Module stage ladder

Stage 0   features/profile.tsx
Stage 1   features/checkout/public/ + internals
Promotion services/cart/public/     ← catalog + checkout import
Lift      shared/lib/format-currency.ts  ← 2+ modules, no product logic

More — Modules & public API and Code evolution.

Path aliases

CLI and the ESLint plugin resolve @/src/ from tsconfig.json. Make sure paths are configured at the app root, not the whole monorepo.

What's next

On this page