> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackra.figentra.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 0227 — Rejected and deferred technologies, refreshed

> Accepted, amended by 0267 · 2026-10-20

> [!NOTE]
>
> Supersedes [0011](/adr/0011-rejected-and-deferred-technologies). Every row change that earlier
> ADRs made to the 0011 table is collected here, so the table has one source again. The rows that
> changed are named in Decision.

> [!NOTE]
>
> Amended by [0267](/adr/0267-infisical-agent-vault-deferred): a row is added for Agent Vault, which
> is deferred. The row changes only by a new ADR, and 0267 is that ADR.

## Context

[0011](/adr/0011-rejected-and-deferred-technologies) is the one table of rejected and deferred technologies. Since it
was written, waves 1 to 3 added or changed rows in separate ADRs: the Encore row ([0124](/adr/0124-encore-is-the-generated-runtime-target)),
the runtime schema engine ([0110](/adr/0110-experience-is-the-sdui-service-at-l2), [0154](/adr/0154-tenant-code-runs-only-in-a-sandboxed-code-step)),
the delegation row ([0193](/adr/0193-agents-and-model-policy)), and others. A reader had to read sixteen ADRs to learn one
row. The owner's answers also added rows that the table never held (Better Auth, Storybook, GraphQL and others).

## Decision

1. **One table.** The table below replaces the 0011 table. Do not introduce anything in the **Not introduced** column. If a
   task seems to need one, stop and route to the owner. Rejected means no. Deferred means not yet, and the trigger names when.
   A row changes only by a new ADR.
2. **Rows changed.**
   * The Encore row is the hand-written form only: `encore.dev` and `~encore/*` in service members are rejected, and Encore is the
     generated target in `.stackra/encore` ([0091](/adr/0091-generated-encore-app-in-stackra-folder), [0124](/adr/0124-encore-is-the-generated-runtime-target)).
   * The delegation row is removed. Agents run by tier under [0193](/adr/0193-agents-and-model-policy).
   * The AI gateway row is reworded. An LLM proxy gateway in front of model providers stays rejected. One MCP gateway in the
     ai service is allowed ([0155](/adr/0155-queries-are-mcp-tools-and-all-ai-code-is-free)).
   * The search row: OpenSearch is built on a measured trigger ([0221](/adr/0221-search-postgres-hybrid-elasticsuite-parity-arabic-and-operations)).
   * The authorization row: the OpenFGA and OPA adapters come later, behind the policy decision point ([0208](/adr/0208-iam-model-scope-tree-roles-conditions-deny-delegation-and-permission-names)).
   * The shared component row: the replacement is the `@stackra/ui` contract ([0165](/adr/0165-web-client-stack-ui-contract-form-adapters-and-no-nextjs)).
   * The observability row points to [0184](/adr/0184-telemetry-opentelemetry-otlp-slis-heartbeats-and-log-retention).
   * The runtime schema engine row adds the allowed forms that later ADRs record: tenant content types ([0226](/adr/0226-content-tenant-defined-types-at-runtime-and-headless-delivery)),
     tenant automations ([0153](/adr/0153-automations-run-as-principals-and-every-package-exposes-building-blocks)), and pricing blocks with no expressions ([0219](/adr/0219-the-merchant-account-chain-and-registered-price-models)).
3. **Rows added.** Better Auth, change-data-capture, XState, Storybook, GraphQL, hand-written gRPC, the Kafka/NATS/Redpanda bus
   drivers, and the deferred platform items: a vector store, a graph database, an OLAP engine, sharding, a second non-TypeScript
   runtime. Active-active across regions is rejected ([0186](/adr/0186-backups-and-disaster-recovery)).

## Table

| Not introduced | Status | Use instead | Revival trigger |
| - | - | - | - |
| Hand-written Encore (`encore.dev`, `~encore/*`, `encore.*` files) in service members | Rejected | Plain TypeScript service members; Encore generated by `stackra gen` into `.stackra/encore` ([0091](/adr/0091-generated-encore-app-in-stackra-folder), [0124](/adr/0124-encore-is-the-generated-runtime-target)) | None foreseen |
| Nest.js (`@nestjs/*`) as a framework layer | Rejected | `@stackra/container` (Nest-shaped, no `@nestjs/*`, [0005](/adr/0005-di-container-and-legacy-decorators)) | None foreseen |
| A separately run gateway product or service in front of services (Kong, Envoy, an own gateway service) | Rejected | The generated Encore gateway and edge ([0237](/adr/0237-generated-api-gateway-in-four-layers)) | None foreseen |
| `reflect-metadata` and type-based auto-wiring | Rejected | Explicit tokens ([0005](/adr/0005-di-container-and-legacy-decorators)) | A hosts-wide toolchain that emits `design:paramtypes` everywhere |
| Prisma, Drizzle, TypeORM, Knex | Rejected | MikroORM on the server ([0014](/adr/0014-data-ownership-and-orm)) | MikroORM fails a measured requirement and the ADR names the replacement |
| MikroORM or any ORM on a client | Rejected | Client storage is `@stackra/storage` ([0256](/adr/0256-client-storage-one-stackra-storage-package)) | Never on a client |
| ESLint, Prettier, Jest | Rejected | oxlint, oxfmt, vitest ([0001](/adr/0001-monorepo-layout)) | A required rule or feature the Oxc tools lack, shown by a failing case |
| Express, Fastify as a server framework | Rejected | The service runtime chosen by ADR | Same as the runtime row |
| Tauri as the desktop shell | Rejected | Electron ([0058](/adr/0058-desktop-is-electron)), one app member with a desktop target ([0249](/adr/0249-one-app-three-targets-web-pwa-and-electron)) | None foreseen |
| Next.js (`next`, the `app-next` app kind) | Rejected | Vite with React Router 7 framework mode, which covers server rendering ([0165](/adr/0165-web-client-stack-ui-contract-form-adapters-and-no-nextjs)) | Never. Change only by a new ADR |
| Vite+ (`vp`) as the task runner | Rejected | Turborepo, oxlint, oxfmt, lefthook | Turborepo stops meeting cache or boundary needs |
| A second vault or Doppler; secret values in any file | Rejected | Infisical plus the runtime secret store ([0173](/adr/0173-secrets-infisical-is-the-source-of-production-secrets)) | Infisical is retired by the organisation |
| Two code hosts in one repository | Rejected | One host ([0012](/adr/0012-code-host-and-ci)) | A migration ADR that deletes the first host in the same change |
| An LLM proxy gateway in front of model providers; a separate-language agent runtime (LangGraph and similar) | Rejected | AI SDK core plus MCP SDK in the service; one MCP gateway in the ai service ([0155](/adr/0155-queries-are-mcp-tools-and-all-ai-code-is-free), [0021](/adr/0021-ai-engine-and-agent-write-safety)) | A provider requirement the SDK cannot meet |
| A shared React component library across web and native | Deferred | Share types, client, validation, state, i18n and tokens, and the `@stackra/ui` contract ([0165](/adr/0165-web-client-stack-ui-contract-form-adapters-and-no-nextjs)) | Two apps ship the same screen and the duplication has caused a bug |
| A sync engine (RxDB, ElectricSQL, PowerSync, WatermelonDB) | Deferred | A mutation queue with idempotency keys; conflict records for human review | Offline editing of shared records is a product requirement |
| A dedicated search service (Typesense, Meilisearch, OpenSearch) | Deferred | Postgres hybrid search behind a search interface ([0221](/adr/0221-search-postgres-hybrid-elasticsuite-parity-arabic-and-operations)) | OpenSearch: a tenant index passes about one million documents, or facets must return in under 50 ms. Other engines need a new ADR |
| A relationship-authorization service (OpenFGA, SpiceDB, Cedar) | Deferred | An in-house check shaped like `check(subject, relation, object)`, behind the policy decision point; OpenFGA and OPA adapters later ([0208](/adr/0208-iam-model-scope-tree-roles-conditions-deny-delegation-and-permission-names)) | More than one service needs shared, queried authorization data |
| A dedicated observability service or Prometheus for business metrics | Deferred | Platform tracing, metrics and logs ([0184](/adr/0184-telemetry-opentelemetry-otlp-slis-heartbeats-and-log-retention)) | Business metrics need retention the platform tooling does not give |
| A runtime schema engine, JSONB-for-everything, or tenant data that carries code, markup or logic | Rejected | Coded resources and build-time generation. Allowed: data that only references registered code, namely L2 UI documents ([0110](/adr/0110-experience-is-the-sdui-service-at-l2)), builder-UI agents ([0100](/adr/0100-ai-model-and-ownership)), tenant automations ([0122](/adr/0122-workflow-studio-three-layers), [0153](/adr/0153-automations-run-as-principals-and-every-package-exposes-building-blocks)), bounded custom fields ([0116](/adr/0116-content-types-and-custom-fields)), tenant content types ([0226](/adr/0226-content-tenant-defined-types-at-runtime-and-headless-delivery)), pricing blocks with no expressions ([0219](/adr/0219-the-merchant-account-chain-and-registered-price-models)), and the sandboxed code step for tenant logic ([0154](/adr/0154-tenant-code-runs-only-in-a-sandboxed-code-step)) | None foreseen |
| Better Auth as the identity provider | Rejected | ZITADEL is the one identity provider ([0206](/adr/0206-zitadel-is-the-identity-provider-and-stackra-identity-is-provider-neutral)) | None foreseen |
| Change-data-capture tools (Debezium and similar) | Rejected | The transactional outbox (`@stackra/outbox`) and integration events; audit through pgaudit and `@AccessLogged` ([0212](/adr/0212-audit-evidence-access-logs-hash-chain-and-retention)) | None foreseen |
| XState or another external state-machine library | Rejected | `@stackra/state-machine`, typed in-house ([0161](/adr/0161-state-machine-package)) | None foreseen |
| Storybook and `*.stories.*` files | Rejected | Nothing replaces it; stories files are banned ([0128](/adr/0128-code-conventions-enums-classes-components-and-kind-folders)) | A new ADR, as Storybook was rejected by the owner |
| GraphQL | Rejected | One declaration per action, exposed as MCP tools first and as REST from the same declaration ([0217](/adr/0217-api-surfaces-mcp-first-plus-rest-sdks-and-rate-limits)) | None foreseen |
| Hand-written gRPC | Rejected | A transport driver behind the port ([0142](/adr/0142-cross-service-transport-through-drivers)) | None foreseen |
| Kafka, NATS or Redpanda as the bus | Deferred | The event-bus port with its current driver ([0142](/adr/0142-cross-service-transport-through-drivers)) | A measured throughput or fan-out limit the current driver cannot meet. No trigger is recorded in 0142 yet |
| A vector store as a separate service | Deferred | pgvector in Postgres, an approved extension ([0160](/adr/0160-raw-sql-at-runtime-and-the-approved-postgres-extensions)) | A measured CPU or latency limit that TypeScript and Postgres cannot meet |
| A graph database | Deferred | ltree in Postgres, an approved extension ([0160](/adr/0160-raw-sql-at-runtime-and-the-approved-postgres-extensions)) | A measured CPU or latency limit that TypeScript and Postgres cannot meet |
| An OLAP engine | Deferred | Postgres with the approved extensions ([0160](/adr/0160-raw-sql-at-runtime-and-the-approved-postgres-extensions)) | A measured CPU or latency limit that TypeScript and Postgres cannot meet |
| Database sharding | Deferred | One region and one primary; cells come later ([0186](/adr/0186-backups-and-disaster-recovery)) | A measured CPU or latency limit that TypeScript and Postgres cannot meet |
| Active-active across regions | Rejected | One region; cells come later ([0186](/adr/0186-backups-and-disaster-recovery)) | None foreseen |
| A second non-TypeScript runtime for services | Deferred | TypeScript service members ([0010](/adr/0010-services-are-independent-workspace-members)) | A measured CPU or latency limit that TypeScript cannot meet |
| Agent Vault (Infisical proxy for coding-agent and AI egress credentials) | Deferred | `direct` egress and the `/agents` vault paths; the revival trigger is in [0267](/adr/0267-infisical-agent-vault-deferred) | |

## Consequences

* A proposal that touches one of these rows starts with a new ADR, not a pull request.
* Product-specific rejections (billing vendors, wallet design and similar) are not carried here; a product repository records its own.
* The Temporal driver stays as the Pro driver ([0151](/adr/0151-workflow-engine-is-a-port-with-native-and-temporal-drivers)); this table does not list it.

## Enforcement

* `FORBIDDEN_DEPENDENCIES` in `tools/scripts/validate-repository.mjs` fails a member that lists `eslint`, `prettier`, `jest`,
  `@nestjs/core`, `@nestjs/common`, `reflect-metadata`, `prisma`, `@prisma/client`, `drizzle-orm`, `express`, `fastify`, `typeorm` or `knex`.
* `packages/tooling/oxlint/src/boundaries.jsonc` bans `encore.dev` in packages.
* planned — extend `FORBIDDEN_DEPENDENCIES` with `next`, `better-auth`, `xstate`, `@storybook/*` and `graphql`, the rows this table adds.
* The `architecture-guardian` agent reads this page.

## Alternatives

* Leave the scattered row changes in their own ADRs and keep 0011 as it is. Rejected, because a reader would need sixteen ADRs to learn one row.

## Supersedes and sources

Supersedes: [0011](/adr/0011-rejected-and-deferred-technologies). Sources: the wave 4 entry for 0227 in the decision register (gap B18, row changes C-24 and the 0193 delegation row); owner answers on Next.js, Better Auth and the identity provider (`stackra-decisions-2026-10-19.md`, 2026-10-20).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.