Skip to main content

Global resources

Most of an environment's resources are regional: defined once and instantiated into every region listed in regions.yaml (see Resources overview). Some resources, though, should exist once — a database every region reads, a host with no regional twin. Those go in the global slice.

The global slice is not a new resource kind. It is a reserved, region-less scope: the same resource types, the same schemas, the same providers — deployed once instead of per region.

On-disk shape

The global slice lives under resources/<env>/global/, mirroring the regional type directories. Each resource is a named folder containing manifest.yaml, same as regional resources:

resources/<env>/
variables.yaml
regions.yaml
regional/
network/ compute/ database/ service/ # the regional set (per region)
global/
network/<name>/manifest.yaml # the global slice (once)
compute/<name>/manifest.yaml
database/<name>/manifest.yaml
service/<name>/manifest.yaml
environment.yaml

The slice is optional — an environment with no global/ directory deploys nothing globally.

Provider config: the global: block

A global resource realizes against a top-level global: block in regions.yaml. It carries a required placementRegion and a providers block. There is no slug — global resources are region-less — but placementRegion names the region whose provider credentials and realizations will be used when deploying global resources (validated now; runtime wiring in a follow-up):

resources/prd/regions.yaml
regions:
us-east-1:
slug: use1
providers:
neon: { apiKey: ${NEON_API_KEY} }
infisical: { clientId: ${INFISICAL_CLIENT_ID}, clientSecret: ${INFISICAL_CLIENT_SECRET} }
global:
placementRegion: us-east-1 # required — must match a key under regions:
providers:
# A global Neon database has no abstract region to map to a physical Neon
# region, so the global block gives it explicitly. (Regional blocks don't
# need this — their abstract region maps to a Neon region automatically.)
neon: { apiKey: ${NEON_API_KEY}, region: aws-us-east-2 }

placementRegion resolves provider-registration lookups only. It does not affect global resource names (no slug is inserted). Omitting it when a global: block is present is a validation error. See ADR-0023.

Region-less naming

Regional resources carry the region slug in their cloud name (wardnet-<env>-<slug>-<type>-<name>). Global resources drop it:

ScopeExample name
Regionalwardnet-prd-use1-db-bridge
Globalwardnet-prd-db-shared

The global slice is created before any region, so its outputs are available when a regional resource references them.

Cross-reference rules

References between scopes are narrow and direction-enforced.

Allowed: a regional secret → a global database/compute output

A regional service secret may resolve a global database or compute output by prefixing the referenced name with global/:

regional/service/app/environment.yaml
DATABASE_URL: ref:database/global/shared.connectionUrl # the global database

This is the one cross-region path: a service in any region reads a database (or compute IP) that lives once, globally. The reference resolves against the global slice regardless of the consuming service's region.

Rejected

ReferenceWhy
service.host: global/<name>A service that runs on a global host is defined in the global slice itself, not referenced from a region.
compute.network: global/<name>Recognized, but cross-region networking is not trivial to materialize and is not supported yet.
A global resource referencing a regional oneWithin the global slice, a global resource may reference only other global resources. The global slice is validated in a global-only context, so a regional name is simply not found.

inforge validate enforces all three with explicit messages.

What realizes today

This slice realizes the global network, compute, and database resources (the referenceable outputs). Global service resources are loaded and validated, but their host-level provisioning is not wired yet — only the output-producing types deploy globally for now. Note that validation still enforces the full rules for these types (e.g. a global service host must declare a deploy_user), even though they do not deploy yet.