Skip to main content
Amended by 0133: model keys, rename-safe fields and lifecycle events. The state machine moves out of @stackra/model to its own package (ADR 0161, wave 1 part 4, not on this branch).

Context

MikroORM is the ORM (0014). Models are decorated classes (0094), and their shapes are needed on the client too: forms, the API client and admin resources. MikroORM’s own decorators would pull the ORM into client bundles. The owner left open where MikroORM lives (Round 9 G1). A Nest ORM wrapper studied as a reference (nestjs-orm, also found at archive/monorepo-main/packages/infra/orm) already has the feature set products expect. The owner compared the plan against it and accepted it with five additions.

Decision

  1. @stackra/model holds the client-safe parts: model and field decorators built on @stackra/validation (0095), relations as metadata, scopes, eager-load declarations, a state machine, createTrait and the trait registry (0096). It imports no ORM.
  2. @stackra/database is the only package that imports @mikro-orm/*.
  3. stackra gen emits MikroORM EntitySchema definitions from model metadata. MikroORM’s decorators are not used.
  4. The feature list is ported from the nestjs-orm reference (its features, not its code): scopes, eager loading, per-audience hidden and visible fields, morph relations, pivots, the trait runtime as a MikroORM subscriber, named filters, three paginators with cursor as the default, chunk, upsert and bulk operations, typed flush errors, factories and seeders, migrate, seed and make commands on @stackra/console, a DataLoader, pruning, and a per-model connection resolver (0088).
  5. Five additions from the reference:
    1. list filtering, sorting and includes, declared on the model and accepted by list actions;
    2. @Stored and @Translatable field storage (where and how a field is persisted, and per-locale values);
    3. the rich CRUD API consumed by @Crud (0105);
    4. the reference’s schema registry, folded into the gen manifest rather than kept as a runtime registry;
    5. a database health check, and factory states.
  6. Read replicas are a new design, not ported.

Consequences

  • Client bundles import model shapes without the ORM.
  • Generated schemas mean ORM changes show up in gen output, not in hand-written mappings.
  • A large feature surface to port and test. Each feature lands with its tests.

Enforcement

Planned: packages/tooling/oxlint/src/boundaries.jsonc bans @mikro-orm/* imports outside @stackra/database, and gen’s --check covers emitted schemas. Nothing checks this today.

Supersedes and sources

Supersedes: none. Answers the open question of Round 9 G1. Sources: recommendation by the coordinating agent, 2026-10-19; accepted by the owner with the five additions (Round 11 O1). Reference: nestjs-orm (/Users/akouta/Downloads/2026/archive/monorepo-main/packages/infra/orm, informational).