Astro
DMA with composition root in pages/ and frontmatter imports.
Example for Astro 5: layers under src/, composition root in src/pages/, layout and providers in src/app/.
Sources: examples/astro-pages.
Two roots: pages and app
| Folder | Role |
|---|---|
src/pages/ | Routes — thin, mount only |
src/app/ | Layout, providers, seed — not routes |
In pages/ — only routable files (index.astro). layout.astro and shop-providers.astro live in app/ so Astro does not create extra routes.
Thin route
---
import CatalogPage from "@/features/catalog/public/catalog-page.astro";
import ShopProviders from "@/app/shop-providers.astro";
import Layout from "@/app/layout.astro";
---
<Layout title="DMA · Astro mini-shop">
<ShopProviders>
<CatalogPage />
</ShopProviders>
</Layout>Imports only downward: features/*/public/*, services/*/public/*, shared/*.
Frontmatter = module script
The --- block runs at build time:
- Import
*/public/*and stage-0 modules - Call service helpers before the template
- Pass data to children via props
dma check and the Biome plugin parse imports from .astro frontmatter the same as from .ts.
Provider pattern
shop-providers.astro binds a port before features render:
---
import { provideCartSeed } from "@/services/cart/public/ports";
import { demoCartSeed } from "@/app/cart-seed";
provideCartSeed(demoCartSeed);
---
<slot />Ports are invisible to the static graph — use for seed/cycle break, not to bypass promotion. More — Cross-module wiring.
State patterns
- Colocated store —
catalog.store.ts, relative import frompublic/ - Promoted service —
services/cart/public/cart.ts(catalog + checkout) - Provider port —
ports.ts+ bind inapp/
Where to put code
| Task | Folder |
|---|---|
| Route shell | src/pages/*.astro |
| Layout, providers | src/app/ |
| Feature screen | features/<name>/public/<entry>.astro |
| Stage-0 module | features/<name>.astro |
| 2+ consumers | services/<name>/public/ |
| Portable UI/lib | shared/ui/, shared/lib/ |
Styles
| Kind | Where |
|---|---|
Scoped <style> | In the same .astro file |
| Feature CSS | colocated *.css → import from public/ |
| CSS Modules | public/*.module.css |
| Global | styles/global.css → import from app/layout.astro |
Global CSS — only from the composition root.
Tooling
bun run build # astro build
bun run dma-check # dma check .
bun run lint # biome + @derived-modular/biome-plugin
bun run testBiome plugin is best-effort (GritQL). No full path resolution or graph cycles. Always run dma check in CI.