Requires

Declares required resource dependencies. The app will not start without them. Value is an array; each entry is a string (shorthand) or an object.

A string shorthand (requires: [postgres]) expands to [{ type: "postgres" }].

An object entry is one of two kinds, distinguished by its marker field: a backing service (has type:) that the provider provisions and wires, or a host capability (has host:) that the provider grants or refuses — see Host capabilities.

Field Type Required Description
name string no Resource name for expression references (defaults to type)
type string yes Resource type (see Resource Property Vocabulary)
endpoint string conditional The provides entry this resource fronts, by its name. Required on a type: https-origin entry; meaningless on any other type — see Public HTTPS origins
version string no Version constraint using semver ranges (e.g. >=15, ^7.0, 20.x)
config map<string, any> no Resource provisioning hints (platform-interpreted)
uses array<string | object> no Which features of the resource the app uses (e.g. [db, pubsub] for redis); a repeatable use may be named more than once (- db: cache) — see Resource uses
set_env map<string, string> no Maps resource properties to app env vars using $ expressions
requires:
  - type: postgres
    version: ">=15"
    set_env:
      DATABASE_URL: $url
      DB_HOST: $host
      DB_PASSWORD: $password

Resource naming

By default, a resource's name is its type. Expression references like $postgres.host use this name. When an app requires multiple instances of the same type, use the name field to distinguish them:

requires:
  - type: postgres
    name: primary-db
    set_env:
      PRIMARY_DB_URL: $url
  - type: postgres
    name: analytics-db
    set_env:
      ANALYTICS_DB_URL: $url

References use the name: $primary-db.host, $analytics-db.host. Without name, two resources of the same type would be ambiguous.

Version constraints

The version field uses semver range syntax (as defined by node-semver):

Syntax Meaning
>=15 Version 15 or higher
^7.0 Compatible with 7.x (>=7.0.0, <8.0.0)
~2.1.0 Approximately 2.1.x (>=2.1.0, <2.2.0)
20.x Any 20.x version
15.2.0 Exact version

Resource configuration

The config map passes provisioning hints to the platform. Keys and semantics are resource-type-specific:

requires:
  - type: postgres
    version: ">=15"
    config:
      extensions: [pgvector, postgis]
      shared_buffers: 256MB
  - type: redis
    config:
      maxmemory: 256mb
      maxmemory-policy: allkeys-lru

The platform interprets these hints when provisioning the resource. Unknown keys are ignored by platforms that don't support them.

Resource uses

requires: redis says the app needs Redis. It does not say what the app needs of it — one keyspace, pub/sub channels, or the whole server. uses states that fact. It is a list of tokens from a small per-type vocabulary (Resource Use Vocabulary):

requires:
  - type: redis
    uses: [db, pubsub]
    set_env:
      CACHE_URL: $redis.db.url          # redis://host:6379/<index>
      CACHE_DB: $redis.db.index         # the integer
      REDIS_URL: $url                   # the instance, as before

Undeclared means what the property vocabulary already promises. A requires: redis entry with no uses is satisfied by any Redis the platform supplies that speaks the property vocabulary — pooled or dedicated — exactly as before; it does not mean a dedicated server. A requires: postgres entry with no uses is one database (name), also as before. An app that needs the whole server declares uses: [server].

Declared uses narrow the need and select the fields. A platform may satisfy the entry from a shared unit only when every declared use fits in that unit; otherwise it provisions, or refuses. Each use registers its own properties, addressed as $<resource>.<use>.<property> — $redis.db.url is the standard Redis URL with the database selected by path (redis://[user:password@]host:port/<index>), $redis.db.index that integer. The entry-level $url, $host, $port and $password keep their meaning: the instance address. A use that registers no property of its own (pubsub, server) is addressed through the instance properties. Inside an entry that declares uses, a $<resource>.<use>.<property> path either resolves from the use's registered properties or is an error — never an empty string, never a fallback to the instance value — so a mistyped use fails at wiring time rather than connecting the app to the wrong database. That error stops generation for the whole app: the provider emits nothing, for any component. It does not skip the single component, which is what a provider does when it cannot cover a declared use (D-64) — a reference to a use the entry never declared is wrong in the file, so no partly-wired deployment is produced.

A provider covers every declared use or refuses the component. A use the provider cannot cover — including a token it does not recognise, since no provider can claim to cover a use it does not know — takes the same refuse branch as a resource type it cannot provision (PROVIDERS.md §10 item 5, D-64): the component is refused before launch, naming the entry and the uncovered use. The vocabulary is open, so a token outside the standard set is a validate warning rather than a validation error — but at deploy time a typo fails the deployment rather than being silently ignored. On a supports: entry the same shortfall leaves the entry unfulfilled with a warning, never refused.

A repeatable use may be named more than once. A use the vocabulary marks repeatable (db on redis, database on postgres and mysql) may appear more than once on one entry, each occurrence written as a single-key map naming it. The name is an expression path segment and takes the name grammar (^[a-z][a-z0-9-]*$):

requires:
  - type: redis
    uses:
      - db: cache
      - db: sessions
      - pubsub
    set_env:
      CACHE_URL: $redis.db.cache.url        # redis://host:6379/<index of cache>
      SESSION_URL: $redis.db.sessions.url   # a different index
      SESSION_DB: $redis.db.sessions.index
      REDIS_URL: $url                       # the instance, as before

Each named use registers the token's properties under its name, addressed as $<resource>.<use>.<name>.<property> — the same nesting $app.endpoints.<name>.<property> uses: $redis.db.cache.url is redis://[user:password@]host:port/<index> with the index allocated to cache, $redis.db.cache.index that integer; $postgres.database.<name>.url is the standard URL with /<database> as its path and $postgres.database.<name>.name that database. A platform hands each named occurrence its own unit — one Redis database per named db, one database per named database — so two names never share one. The entry-level properties keep the instance meaning, and an unnamed single db keeps the three-segment $redis.db.url form: naming is for the entry that needs more than one.

Within one entry a token is declared bare or named, never both — uses: [db, {db: cache}] is invalid, because $redis.db.url and $redis.db.cache.url would then name two different databases under one token; name every occurrence, or declare the token once unnamed. The same name twice on one token is invalid, as a bare token twice is. A name on a use the vocabulary marks non-repeatable (pubsub, server) is a validation error, not a lint warning: the name would promise a second set of channels or a second server the type cannot hand over. A token outside the standard vocabulary may take a name — the vocabulary is open, and whether a provider-defined use repeats is that provider's to say.

The strict resolution rule above extends to the named form. On an entry that names its db uses, $redis.db.url — the bare form — is an error, not the instance URL and not any one of the named databases; $redis.db.nosuch.url names an occurrence the entry does not declare and is an error too. A provider covers each named occurrence or refuses the component, naming the entry, the token and the name; a supplied resource satisfies the entry only when its map carries every registered <use>.<name>.<property> key.

Expression wiring

Values in set_env use the expression syntax. Inside a requires or supports block, bare $prop references resolve against the enclosing resource's property vocabulary.

Real-world examples: See how Ghost, Metabase, and Miniflux declare their database requirements. Browse all apps →

Public HTTPS origins

An app that only works over HTTPS says so with the backing-service type https-origin: browsers reach this app at a public origin whose scheme is https. Like any backing service, the provider provisions and wires it, or refuses — it is not a hint and not a probe.

provides:
  - name: web
    protocol: http
    port: 80
    exposed: true
requires:
  - type: https-origin
    endpoint: web
    set_env:
      DOMAIN: $url

The app's own listener is untouched: protocol: http still describes what the component speaks on its own port (D-59). Where TLS terminates, and which certificate it uses, stay outside the file (D-5, D-15).

Six rules bind the entry:

  1. The type names an interface, never a product. https-origin is an origin whose scheme is https — never caddy, traefik, or acme.
  2. endpoint: names a provides entry by its name (named endpoints). It is required on an https-origin entry and meaningless on any other type. The entry MUST sit on the component that owns the endpoint; at the top level of a file that declares components: it is a validation error, because top-level requires defaults into every component that declares none and one entry would face several provides lists. The name must match exactly one entry on that component; that entry must be exposed: true and declare an HTTP-family listener — http, https, ws, or grpc. Naming a tcp or udp entry is a validation error: those listeners have no origin.
  3. One per app, and it defines "primary". At most one https-origin entry across all components; a second is a validation error. The named endpoint is the app's primary endpoint for $app.* derivation and for orchestrator-supplied publication context (D-58 rule 4). Declaring the entry fixes the primary — whether or not a provider fulfills it — so $app.url never changes value with a provider's capability. It reaches $app.* only: $components.<name>.url is unaffected. With no entry declared, providers keep their own positional choice.
  4. One property: url — the same value as $app.url, from one derivation. No host, port, scheme, authority, or tls property is registered; $app.* already standardises those.
  5. Fulfillment, no probe. The provider provisions the origin, or accepts one supplied through its orchestrator-facing publication channel, or refuses with a clear message. A supplied URL whose scheme is not https is refused. The provider does not verify the origin exists or is reachable. See PROVIDERS.md §7 and §10 item 5.
  6. supports: is the optional mood. Unfulfilled, the entry's set_env is absent and the provider notes the un-granted dependency — the app deploys and degrades.
# mailpit — the endpoint reference takes whatever the app called it
provides:
  - name: web-ui
    protocol: http
    port: 8025
    exposed: true
  - name: smtp
    protocol: tcp
    port: 1025
    exposed: true
supports:
  - type: https-origin
    endpoint: web-ui        # `endpoint: smtp` would be a validation error (rule 2)

A ws endpoint behind an https-origin resolves url to https://…, not wss://…: url is fixed as the https origin for every admitted listener protocol. A wss spelling, if it ever arrives, arrives as a new property, never as a change to what url resolves to.

Host capabilities

A requires/supports entry can request a host capability — a privileged grant from the machine the app runs on — instead of a backing service. A capability entry is marked with host:. The provider grants it (mounts or forwards the underlying coordinate and populates the capability's properties) or refuses the deployment with a clear message; it never provisions anything. See PROVIDERS.md for the provider-side contract.

requires:
  - postgres                              # backing service → provision + wire
  - host: { container_runtime: docker }   # capability      → grant or refuse
    set_env:
      DOCKER_HOST: $url
supports:
  - host: { container_runtime: any }      # optional — deploy, probe, degrade
Field Type Required Description
host map<string, string | bool> yes Capability name → interface value (see Capability vocabulary)
set_env map<string, string> no Maps capability properties to app env vars using $ expressions

Rules:

  • The host: marker is required on every privileged entry. An entry's kind is machine-extractable from the file itself: a bare string or type: entry is a backing service; a host: entry is a capability. Anyone — tooling or a human reviewer — can list an app's full privilege surface with zero extra tooling. launchfile validate prints it as host capabilities requested: […].
  • The value names an interface, never a product. container_runtime: docker means "the Docker Engine API" — a Podman-compatible socket satisfies it — exactly as requires: postgres names a wire protocol, not a vendor. container_runtime: any is runtime-agnostic. The vocabulary is open: unknown capability names and values are tolerated by parsers; a provider that cannot grant a required capability it does not understand refuses.
  • Required vs optional is requires vs supports. A capability in requires must be granted or the provider refuses to deploy the component. A capability in supports is optional: the app deploys without it, probes its env vars at startup, and degrades gracefully.
  • Wiring uses set_env, exactly as for backing services. A granted capability exposes provider-supplied properties (below); bare $prop references inside the entry resolve against the enclosing capability's properties.

Capability properties

Like resource properties, a granted capability exposes a standard set of properties the provider computes from how it granted the capability:

Capability Property Meaning
container_runtime $socket Filesystem path of the runtime socket (e.g. /var/run/docker.sock)
container_runtime $url DOCKER_HOST-style connection string (e.g. unix:///var/run/docker.sock, tcp://10.0.0.5:2376)
container_runtime $api HTTP(S) API endpoint URL, when the runtime is reachable over the network

Properties a provider cannot supply resolve to the empty string, matching unknown resource properties.

Capability vocabulary

Capability Values Meaning
container_runtime docker, any Access to a container-runtime control API. docker = the Docker Engine API (any compatible socket satisfies it, including Podman's); any = runtime-agnostic.
network host Must share the host network stack
filesystem read-write, read-only Host filesystem access
privileged true Elevated privileges (e.g. device access)

network, filesystem, and privileged are the entry-form spelling of the legacy host block keys — they are grant/refuse capabilities like any other. That block is deprecated in launch/v1 and removed in launch/v2 (D-54); entries are the form to write. Existing files using the block stay valid and keep their meaning for the whole of launch/v1 — see Migrating off the host: block.

esc
Type to search the docs