Skip to main content
Accepted (epic STA-1640): owner answers of 2026-10-30 to the spec sta-1640-runway-resources-workloads, Q1 to Q7. Extends 0296 (member requires, root shared) and generalises 0444’s Fargate stack. Keeps 0227’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 decision 4 (self-hosted ZITADEL in a SaaS region that residency forces). Sources: owner decision relayed 2026-10-30; STA-1640.