> ## 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.

# 0493 — Runway resources and workloads: one runway provisions a product's runtime

> Accepted · 2026-10-30

> [!NOTE]
>
> Accepted (epic STA-1640): owner answers of 2026-10-30 to the spec
> `sta-1640-runway-resources-workloads`, Q1 to Q7. Extends
> [0296](https://docs.stackra.figentra.com/adr/0296-runway-v3-member-requires-and-root-topology-groups.md) (member `requires`, root
> `shared`) and generalises
> [0444](https://docs.stackra.figentra.com/adr/0444-one-self-hosted-tools-stack-per-region-from-the-root-runway.md)'s Fargate stack.
> Keeps [0227](https://docs.stackra.figentra.com/adr/0227-rejected-and-deferred-technologies-refreshed.md)'s Kafka and OpenSearch
> deferrals (owner, Q1). Numbered after the highest ADR in flight (0492); the ADR steward reconciles
> the number.

## Context

A product's runtime resources today come from two places. Each service member's runway `requires` an engine, and
the root runway's `environments.<env>.shared` sizes the shared pools. `@stackra/infra-aws-runtime` turns them into
SQS queues, SNS topics, Valkey caches and S3 buckets. The environment's Postgres server (0238) is created by Encore
Cloud through the role `encoreAccess` grants. Self-hosted servers run only in the per-region tools stack (0444),
from a fixed catalogue.

Nothing lets a product declare a database or a container it needs beside its services, size it per
environment, and get its connection details where they are used. Each new need becomes hand-written infrastructure.

## Decision

1. **One root runway declares the runtime.** Two new top-level blocks, both named maps:

   * `resources.<name>`: a managed kind (`postgres`, and the existing `queue`, `topic`, `cache`, `bucket`),
     its engine options, and a size per environment.
   * `workloads.<name>`: a container (image pinned by digest, port, health check, env, secret names, size and scale per
     environment, `uses` of resources, `expose: internal | public`) and a required `reason`.

   A service member or a workload names what it uses (`uses: [main-db]`); the resource does not list its consumers.
   Member `requires` and root `shared` keep working: Runway reads them as implicit resources, so no product breaks.

2. **Runway provisions, per environment, in the product's account** (0172 decision 1). `@stackra/infra-aws-runtime`
   plans each kind (pure, `.`) and declares it with Pulumi (`./node`), as it does for queues and caches. Postgres is
   RDS by default or Aurora, with RDS Proxy in front (0473). Workloads run on one ECS Fargate cluster per environment, with service discovery for `internal` and
   an ALB for `public`. This is the construct 0444's tools stack already uses, extracted and shared.

3. **Sizes come from a catalogue; limits come from the runway.** Each kind has named sizes (`small`, `medium`,
   `large`) in a catalogue that maps to instance classes, capacity and a monthly estimate. Each resource and workload
   picks a size per environment; an environment it does not name runs `small` (dev Postgres is the smallest Graviton
   class, single-AZ). `environments.<env>.limits.monthly` caps the plan's estimate in US dollars, by default $150 in
   dev and $500 in staging: a plan over its cap is refused before anything is created. An environment with no cap,
   production until the owner sets one, only warns with the estimate. AWS Budgets (0172 decision 5) stay the backstop
   for actual spend.

4. **Secrets go to Infisical; consumers get them by name.** A generated credential (a database password) is created
   inside the CI job and written blind to Infisical at `<env>:/runtime/<resource>/` (0482 decision 7). A connection
   string is written there too. Each consumer that `uses` a resource gets fixed variable names
   (`<RESOURCE>_URL`, `<RESOURCE>_PASSWORD`, …): Encore services through the Infisical sync into Encore secrets
   (0173), workloads through SSM parameters the same sync fills (0444 decision 4). RDS Proxy logs in only through
   Secrets Manager, so the admin password is also stored there for the proxy alone; Infisical stays the source. Nobody
   reads a value.

5. **Managed first; a workload needs a reason.** A workload is allowed only when no managed resource or vendor cloud
   fits, when residency forces self-hosting (an in-country region), or for on-prem parity. Its `reason` is required by
   the schema and read in review. Kinds that 0227 defers (Kafka, OpenSearch) are reserved names the schema refuses;
   each comes back through its own trigger (0142 for the bus, 0221 for search) and a new ADR.

6. **Nothing changes AWS without the owner.** Runway's `plan` is data and runs nothing. `pulumi preview` runs in CI,
   and `pulumi up` runs only from the product's `production`-protected deploy job, as every infrastructure change
   does (0352).

## Consequences

* A product adds a database or a container by adding a runway block, not infrastructure code.
* 0444's tools stack moves onto the shared workload construct; its catalogue stays as the defaults of its tools.
* One Postgres server per environment (0238) meets Encore Cloud's own database management. Until the Encore deploy
  path (STA-136) is settled, `resources.postgres` serves workloads and non-Encore consumers, and Encore keeps its own
  (Q2).
* Cost is visible before anything is created, per environment.

## Enforcement

* `@stackra/runway`: the root schema's `resources`, `workloads` and `limits`, with the `reason` refine and the `uses`
  reference check; the canonical schema copy.
* `@stackra/infra-aws-runtime`: plan tests for every kind and size, the cost cap refusal, and Pulumi mock tests of the
  declared resources and the injected secret names.
* planned — STA-1640: a review checklist row that every workload's `reason` names one of the three allowed grounds.

## Supersedes and sources

`Supersedes: none`. Amends
[0206](https://docs.stackra.figentra.com/adr/0206-zitadel-is-the-identity-provider-and-stackra-identity-is-provider-neutral.md) decision 4 (self-hosted
ZITADEL in a SaaS region that residency forces). Sources: owner decision relayed 2026-10-30; STA-1640.


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