Derived Modular Arch
Guides

SvelteKit

DMA with composition root in routes/ and Svelte 5 runes.

SvelteKit + Svelte 5 example: breadth across features, promoted cart service, event wiring in app-providers.svelte.

Sources: examples/sveltekit-routes.

Composition root = routes/

DMA treats src/routes/ as app/:

src/routes/
├── +layout.svelte       # import app.css, mount AppProviders
├── +page.svelte         # thin shell — wiring only
└── app-providers.svelte # theme tokens + event subscriptions

+page.svelte mounts features/*/public/* and stage-0 profile.svelte, promo.svelte.

Event wiring

Checkout emits an event; app subscribes and calls a service:

<!-- routes/app-providers.svelte -->
<script>
  import { onCheckoutCompleted } from "@/features/checkout/public/checkout.events";
  import { clearCart } from "@/services/cart/public/cart";

  onCheckoutCompleted(() => clearCart());
</script>

No checkout → cart as a feature edge — app imports both modules downward. See Cross-module wiring.

Mini-shop flow

  1. Catalogcatalog.store.ts + addCartItem from cart service
  2. Checkout — cart service + checkout.store.ts (payment status)
  3. AppProviderscheckoutCompletedclearCart()
  4. Profile / Promo — stage-0, shared Card

Svelte 5 runes

FileRunes
profile.svelte$state
app-providers.svelte$props, $effect
button.svelte$props

Stores in *.store.ts — regular Svelte stores, auto-subscription via $store.

Where to put code

QuestionPlace
Route shell, layout?src/routes/
UI flow?features/<name>/public/*
Single-feature state?features/<name>/<name>.store.ts
2+ modules?services/<name>/public/*
Portable helper/UI?shared/lib/, shared/ui/
Subscribers / ports?routes/app-providers.svelte

Internals are imported relative from the public/ file of the same feature.

Styles

KindWhere
Global resetsrc/app.css+layout.svelte
Design tokensapp-providers.svelte (--color-* on .app-theme)
Route shellscoped <style> in +page.svelte
Feature pagescoped in public/*.svelte
Shared UIscoped in shared/ui/*.svelte
Feature sheetcheckout/checkout.css → import from public/

Tokens in the provider shell — features and shared/ui read var(--…) without importing each other.

Tests

Colocated *.test.ts (Vitest):

  • catalog.store.test.ts — store + svelte/store
  • services/cart/public/cart.test.ts — service API
  • shared/lib/format-currency.test.ts — pure helper

dma check scans *.test.ts too — imports in tests follow the same rules. In the example, tests are colocated and import relative inside the module or via public/.

Commands

bun run dev
bun run build
bun run dma-check   # dma check .
bun run lint        # oxlint + @derived-modular/oxlint-plugin
bun run test

What's next

On this page