Template reference
The platform/v1 EnvironmentTemplate format. Metadata and tags, placement slots, variables, every resource type with defaults and limits, and examples.
A template describes intent, never provider resource blocks. The schema on this page comes from
packages/templates/src/schema.ts, the source of truth for the API, the console builder and the
CLI.
apiVersion: platform/v1
kind: EnvironmentTemplate
metadata:
name: hello
version: 1.0.0
displayName: Hello
tags: [starter]
spec:
placements:
- name: primary
providers: [aws]
resources:
- id: api
type: compute.container-service
image: catalog://hello-api
port: 8080
public: trueIdentifiers
Resource ids, slot names and variable names match ^[a-z][a-zA-Z0-9-]{0,39}$. They start with a
lowercase letter, continue with letters, digits and dashes, and have at most 40 characters.
metadata
| Field | Type | Default | Notes |
|---|---|---|---|
name | string | required | ^[a-z][a-z0-9-]{1,62}$, unique per installation. |
version | string | required | Semantic version MAJOR.MINOR.PATCH. |
displayName | string | required | Shown in the console. |
description | string | "" | |
nonProduction | boolean | false | Shows a warning. The non-production-template policy fails it for production instances. |
tags | string[] | [] | Free form labels for search and the marketplace, at most 20: lowercase letters, digits and spaces, up to 32 characters each (starter, postgres, object storage). |
profile | string | none | Deprecated: accepted and ignored with the warning PROFILE_DEPRECATED; rejected from the next release. Move the value to tags. |
spec
| Field | Type | Default | Notes |
|---|---|---|---|
plans | string[] | none | Deprecated: accepted and ignored with the warning PLANS_DEPRECATED; rejected from the next release. A tenant's limits decide what fits, not a list in the template. |
placements | slot[] | required, at least 1 | See placements. |
variables | variable[] | [] | See variables. |
resources | resource[] | required, at least 1 | See resources. |
connectivity | requirement[] | [] | See connectivity. |
observability | object | all on except traces | See observability. |
Placements
A placement slot is a named group of resources that an instance binds to one cloud target and region.
| Field | Type | Default | Notes |
|---|---|---|---|
name | id | required | Resources refer to it in their placement field. |
description | string | ||
providers | enum[] | [] (any) | Allowed providers: aws, azure, gcp, oci, digitalocean, vultr, coreweave, magalu, vercel, render, supabase, mock. An empty list allows any registered provider. See providers. |
placements:
- name: primary
description: Application runtime, registry, ingress and DNS.
providers: [aws, mock]
- name: data
description: Relational database.
providers: [aws, azure, mock]A network binds implicitly only to resources in its own slot. A database placed on another cloud therefore does not depend on the AWS VPC.
Variables
| Field | Type | Default | Notes |
|---|---|---|---|
name | id | required | |
description | string | ||
type | enum | required | number, string, boolean. |
default | number, string or boolean | required | |
min, max | number | For number variables. | |
allowed | string[] | For string variables. | |
target | string | required | The field the variable sets, as <resourceId>.<field>, for example api.replicas. |
variables:
- name: apiReplicas
type: number
default: 1
min: 1
max: 2
target: api.replicas
- name: databaseSize
type: string
default: small
allowed: [micro, small, medium]
target: database.sizeResources
Every resource has these common fields, plus the fields of its type.
| Field | Type | Default | Notes |
|---|---|---|---|
id | id | required | Unique in the template. Physical names use it: ork-<tenant>-<instance>-<id>. |
type | enum | required | One of the nine types below. |
placement | id | primary | The slot this resource belongs to. |
implementation | string | resolver's default | Preferred capability, for example ecs-fargate, ecs-ec2 or rds-postgres. |
enabled | boolean | true | A disabled resource stays in the template, so a variable can turn it on, but is never provisioned. |
dependsOn | id[] | [] | Explicit dependencies. OrkStage adds the implicit ones (network, ingress routes, DNS target). |
overrides | map of maps | Escape hatch for settings of one provider, such as { aws: { … } }. Less portable, and for admins only. |
network
| Field | Type | Default | Notes |
|---|---|---|---|
strategy | enum | isolated | isolated or shared. |
availabilityZones | integer | 1 | 1 to 3. |
natGateway | boolean | false | Private egress through NAT. Adds one NAT gateway per availability zone, which adds cost. |
compute.container-service
| Field | Type | Default | Notes |
|---|---|---|---|
image | string | required | Catalog reference such as catalog://orders-api. It resolves to an immutable digest at deploy time. |
replicas | integer | 1 | 0 to 100. |
cpu | number | 0.25 | vCPU, more than 0 and at most 16. |
memoryMiB | integer | 512 | 128 to 122880. |
port | integer | 1 to 65535. | |
public | boolean | false | Reachable through an ingress. |
healthCheckPath | string | Must start with /. | |
autoscaling | object | { minReplicas, maxReplicas, targetCpuPercent }, with targetCpuPercent from 10 to 95. | |
critical | boolean | true | When a critical component is unhealthy, the instance is unhealthy. |
AWS implementations: ecs-fargate (the default) and ecs-ec2.
On AWS, autoscaling becomes an Application Auto Scaling target with a target tracking policy on
CPU for the ECS service. MiniStack does not emulate autoscaling. There the service runs a fixed
number of tasks (replicas) and the deployment logs a warning.
container-registry
| Field | Type | Default |
|---|---|---|
scanOnPush | boolean | true |
immutableTags | boolean | true |
database.postgresql
| Field | Type | Default | Notes |
|---|---|---|---|
version | string | "17" | Major version. |
size | enum | small | micro, small, medium, large, xlarge. |
storageGiB | integer | 20 | 1 to 16384. |
highAvailability | enum | none | none, same-zone, zone-redundant. On AWS, RDS supports only zone-redundant, which turns on the RDS multi_az setting. |
publicAccess | boolean | false | The no-public-database policy fails a database with true. |
backup | object | { enabled: true, retentionDays: 7 } | retentionDays is 0 to 35. recoveryPointObjectiveMinutes is optional. |
critical | boolean | true |
cache.redis
| Field | Type | Default | Notes |
|---|---|---|---|
size | enum | micro | micro, small, medium, large. |
replicas | integer | 0 | 0 to 5. |
critical | boolean | false |
AWS implementation: ElastiCache with the Valkey engine, which is compatible with Redis OSS.
queue
| Field | Type | Default |
|---|---|---|
fifo | boolean | false |
deadLetter | boolean | true |
critical | boolean | false |
object-storage
| Field | Type | Default | Notes |
|---|---|---|---|
tier | enum | standard | standard, infrequent, archive. |
versioning | boolean | false | |
publicAccess | boolean | false | The no-public-storage policy fails a bucket with true. |
retentionDays | integer | Lifecycle expiration, in days. | |
accessKeys | boolean | false | Create an access key limited to this bucket and keep it in the provider's secret store, for consumers on other providers (a Vercel or Render app). Services on the same provider use their own identity instead. |
critical | boolean | false |
ingress
| Field | Type | Default | Notes |
|---|---|---|---|
routes | route[] | required, at least 1 | { service, pathPrefix }. service is the id of a container service. pathPrefix defaults to /. |
tls | boolean | true |
dns
| Field | Type | Default | Notes |
|---|---|---|---|
target | id | required | The ingress this name points to. |
subdomain | boolean | true | A name under the platform zone, for example production-acme.apps.example.com. |
customDomain | enum | disabled | disabled, optional, required. |
web.frontend
A website, landing page or web app built from a Git repository by a frontend platform (Vercel projects, Render static sites).
| Field | Type | Default | Notes |
|---|---|---|---|
source.repository | string | required | owner/name on the platform's connected Git provider. |
source.branch | string | main | |
source.rootDirectory | string | Folder of the app inside a monorepo. | |
source.gitProvider | enum | github | github, gitlab, bitbucket. |
framework | string | Preset such as nextjs, vite or astro; detected when omitted. | |
buildCommand, installCommand, outputDirectory | string | Override the preset. | |
nodeVersion | string | 22 or 22.x. | |
environment | map | {} | Plain settings, keys in UPPER_SNAKE_CASE. Never put credentials here. |
domains | string[] | [] | Custom domains, up to 20. |
previewDeployments | boolean | true | A preview build for each pull request, where supported. |
healthCheckPath | string | / | Path the health check requests. |
critical | boolean | true |
Resources listed in dependsOn reach the frontend as environment variables. Connection settings
arrive in plain text (<ID>_HOST, <ID>_PORT, <ID>_URL, <ID>_BUCKET, <ID>_ENDPOINT,
<ID>_REGION); credentials a dependency publishes arrive as encrypted values, one per field
(<ID>_URL, <ID>_USERNAME, <ID>_PASSWORD, <ID>_ACCESS_KEY_ID, <ID>_SECRET_ACCESS_KEY, and
so on), read from the provider that owns the dependency at deploy time. <ID> is the resource id
in upper case with dashes turned into underscores.
- id: web
type: web.frontend
placement: web
source: { repository: acme/website, branch: main }
framework: nextjs
environment: { NEXT_PUBLIC_APP_NAME: Acme }
dependsOn: [database, files]Connectivity
| Field | Type | Default | Notes |
|---|---|---|---|
from, to | id | required | Resource ids. |
protocol | enum | required | tcp, http, https, postgres, redis, amqp. |
port | integer | 1 to 65535. | |
mode | enum | private-preferred | private-required, private-preferred, secure. |
When the two resources are on different clouds, private-preferred falls back to TLS over a public
endpoint with an allowlist. The plan rejects private-required across clouds. See
connectivity in the plan review.
connectivity:
- { from: api, to: database, protocol: postgres, port: 5432, mode: private-preferred }
- { from: api, to: storage, protocol: https, mode: secure }Triggers
A trigger is a named action on one deployed resource, with default parameters: redeploy a
frontend, restart a service, take a database restore point. The provider decides which actions
exist; the console and GET /instances/{id}/triggers list them with their parameters.
| Field | Type | Default | Notes |
|---|---|---|---|
name | id | required | Unique in the template. |
description | string | ||
resource | id | required | The resource the action runs on. |
action | string | required | For example redeploy, restart, rollback, purge-cache, backup. |
params | map | {} | Default parameters, checked against the action when it runs. |
overridable | string[] | [] | Parameters a caller may change at run time. Anything else is rejected. |
on.manual | boolean | true | Run from the console or the CLI. |
on.webhook | boolean | false | Run with an API key holding instances:deploy, for example from CI or a CMS. |
on.schedule | cron | Five field cron expression in UTC, for example 0 3 * * *. |
triggers:
- name: redeploy-site
resource: web
action: redeploy
params: { target: production }
overridable: [ref]
on: { manual: true, webhook: true }
- name: nightly-backup
resource: database
action: backup
on: { manual: false, schedule: '0 3 * * *' }See triggers for running them and following their runs.
Observability
| Field | Default |
|---|---|
logs | true |
metrics | true |
traces | false |
uptime | true |
alerts | true |
Example: the multicloud reference
This example places the API on AWS, the database on Azure and object storage on OCI. Bind each slot to a real target of that provider, to a simulation target that imitates it, or bind every slot to the same AWS target for the AWS only variant. The Azure and OCI adapters are in preview (see providers).
apiVersion: platform/v1
kind: EnvironmentTemplate
metadata:
name: multicloud-reference
version: 1.0.0
displayName: Multi-cloud reference
description: >
API on AWS ECS Fargate behind an ALB with ECR and Route 53, Postgres on Azure Flexible Server,
object storage on OCI. Bind every slot to the same AWS target for the AWS-only variant.
tags: [growth, multicloud]
spec:
placements:
- name: primary
description: Application runtime, registry, ingress and DNS.
providers: [aws, mock]
- name: data
description: Relational database.
providers: [aws, azure, mock]
- name: storage
description: Object storage.
providers: [aws, oci, mock]
resources:
- id: network
type: network
availabilityZones: 2
- id: registry
type: container-registry
implementation: ecr
- id: api
type: compute.container-service
implementation: ecs-fargate
image: catalog://sample-api
replicas: 2
cpu: 0.5
memoryMiB: 1024
port: 8080
public: true
healthCheckPath: /health
- id: worker
type: compute.container-service
implementation: ecs-ec2
image: catalog://sample-worker
replicas: 1
cpu: 0.5
memoryMiB: 1024
critical: false
- id: database
type: database.postgresql
placement: data
size: small
storageGiB: 50
highAvailability: zone-redundant
backup: { enabled: true, retentionDays: 7 }
- id: storage
type: object-storage
placement: storage
tier: standard
versioning: true
- id: ingress
type: ingress
routes:
- service: api
- id: dns
type: dns
target: ingress
connectivity:
- { from: api, to: database, protocol: postgres, port: 5432, mode: private-preferred }
- { from: worker, to: database, protocol: postgres, port: 5432, mode: private-preferred }
- { from: api, to: storage, protocol: https, mode: secure }
observability: { logs: true, metrics: true, traces: true, uptime: true, alerts: true }Validating from your machine
curl -X POST "$ORK_API_URL/api/v1/templates/validate" \
-H "Authorization: Bearer $ORK_TOKEN" -H "Content-Type: application/json" \
--data "$(jq -Rs '{source: .}' < template.yaml)"