Skip to content

Deploy YAML — field reference

The complete podmaker.sh/v1alpha manifest, field by field. The schema is strict: unknown keys are rejected everywhere.

Top level

FieldTypeRequiredNotes
apiVersionstringMust be podmaker.sh/v1alpha
kindenumSite or Stack
metadataobjectSee below
targetsarraySiteWhere the site runs (≥ 1)
sourceobjectSiteWhere the code/image comes from
runtimeobjectSiteHow it runs
domainsarrayHostnames + DNS + SSL
envmapEnvironment variables
deployobjectDeploy strategy and hooks
firewallobjectInbound rules
scalingobjectAutoscaling bounds
stackobjectStackMulti-component spec

kind: Site requires targets, source, runtime. kind: Stack requires stack.

metadata

metadata:
name: acme-web # required, ^[a-z][a-z0-9-]{0,62}$
workspace: acme # ^[a-z][a-z0-9-]{0,40}$
tags: [production, web, eu] # ≤ 20 items, each ≤ 32 chars
annotations:
team: platform

targets

Each entry is either a named server or a selector — not both.

targets:
- server: prod-eu-web-01 # explicit server
- server_selector: # or match by attributes
tags: [web, eu]
provider: aws
region: eu-central-1
min: 2
max: 6

source

One of git or image.

# git source
source:
type: git
repo: git@github.com:acme/web.git
branch: main # default: main
ref: <commit-or-tag> # optional, pins an exact ref
auth: # ValueRef — see below
from_vault: secret/acme/web#deploy_key
# image source
source:
type: image
image: registry.podmaker.sh/acme/api:v1.4.2 # must be name:tag
pull_secret:
from_vault: secret/acme/registry#dockerconfig

runtime

runtime:
type: node # node|php|python|ruby|go|java|dotnet|rust|static|container
version: "20"
package_manager: pnpm
build:
command: pnpm install --frozen-lockfile && pnpm build
output_dir: dist
hosted: true # build on a hosted runner (default: false)
start:
command: node server.js
port: 3000 # 1–65535
healthcheck: /healthz

static and container runtimes typically omit build; container runs the image directly with a start.port.

domains

domains:
- hostname: acme.com
dns:
provider: cloudflare
proxy: true # default: false
ssl:
provider: letsencrypt # letsencrypt|zerossl|buypass (default: letsencrypt)
challenge: http-01 # http-01|dns-01 (default: http-01)

env

A map of KEY: value, where each value is a ValueRef — an inline string, a vault reference, or an env reference.

env:
NODE_ENV: production # literal
DATABASE_URL:
from_vault: secret/acme/webdb#url # resolved at deploy time
BUILD_ID:
from_env: CI_COMMIT_SHA # from the deploy environment

from_vault follows the pattern path#key; see Vault & Secrets.

deploy

deploy:
strategy: blue-green # blue-green|rolling|recreate (default: rolling)
rollback_on_failure: true # default: true
hooks:
pre_deploy: ["./scripts/migrate.sh"]
post_deploy: ["./scripts/warm-cache.sh"]
health:
timeout: 90s # ^\d+[smh]$ (default: 60s)
retries: 5 # default: 5

firewall

firewall:
inbound:
- { port: 80, source: "0.0.0.0/0" } # protocol default: tcp
- { port: 443, protocol: tcp, source: "0.0.0.0/0" }

scaling

scaling:
min: 2
max: 10
metric: cpu # cpu|memory|rps|custom
target: 70 # 1–100

stack (kind: Stack)

A Stack groups components and optional shared services.

apiVersion: podmaker.sh/v1alpha
kind: Stack
metadata:
name: acme-platform
stack:
components:
- name: web
source: { type: git, repo: git@github.com:acme/web.git }
runtime: { type: node, version: "20", start: { port: 3000 } }
depends_on: [api]
- name: api
source: { type: image, image: registry.podmaker.sh/acme/api:v1.4.2 }
runtime: { type: container, start: { port: 8080 } }
shared_services:
database: { engine: postgres, version: "16", plan: small } # plan: nano|micro|small|medium|large
cache: { engine: redis, version: "7" }
queue: { engine: rabbitmq }

Each component takes the same source, runtime, targets, domains, env, deploy and scaling fields as a Site, plus depends_on for ordering.

ValueRef

Anywhere a secret-bearing value is accepted (source.auth, source.pull_secret, env.*), you can use one of:

literal-string
{ from_vault: "path/to/secret#key" }
{ from_env: "ENV_VAR_NAME" }

See worked examples next.