pagifier.yaml reference
Two kinds of file exist. The root file lists deployable projects (nothing is ever auto-discovered); each project file completely defines one deployment.
TOML is the primary format (pagifier.toml); YAML
(pagifier.yaml) is fully supported with identical keys — Pagifier
detects the format from content. Get editor autocomplete with the
published JSON Schema:
#:schema https://pagifier.company.com/v1/schema/pagifier.json
# yaml-language-server: $schema=https://pagifier.company.com/v1/schema/pagifier.json
Root file
version = 1
projects = [
"frontend/pagifier.toml",
"admin/pagifier.toml",
"api/pagifier.toml",
]
Project file
| Key | Required | Notes |
|---|---|---|
version | yes | Must be 1. |
name | yes | Lowercase DNS label; becomes the workload name. |
environment | yes | dev qa uat staging prod preview. Selects the environment profile. preview apps are ephemeral: hostname auto-generated, garbage-collected after a TTL. |
runtime | yes* | static, node, python, or go. *May be supplied by the template. |
template | no | Platform template, optionally pinned: react-static@2. |
ha | no | true adds minimum replicas, anti-affinity, topology spread, a PodDisruptionBudget, and zero-downtime rollout. |
port | yes* | Container port. Never guessed. *Node apps may use runtimeConfig.port instead. |
autoRollback | no | true reverts automatically when a rollout stalls. Usually set by environment profiles. |
build.enabled | no | false packages the uploaded artifact as-is. |
build.workDir, build.commands | with build | Commands run verbatim in the toolchain image. Never inferred. |
artifact.directory | static | Directory shipped into the image — nothing else leaves the build. Optional for server runtimes (e.g. ship only a compiled Go binary). |
server.type | no | nginx (the only static server); defaulted when omitted. |
runtimeConfig.command | server runtimes | Mandatory start command for node/python/go. package.json, requirements.txt, and go.mod are never read. |
resources | no | cpu, memory (requests), cpuLimit, memoryLimit. Memory limit defaults to the request. |
ingress | no | host (required if enabled), path, className, tls (default on), annotations. mode: gateway renders a Gateway API HTTPRoute; the parent gateway: {name, namespace, sectionName} usually comes from the environment profile. |
autoscaling | no | enabled, minReplicas, maxReplicas, cpu, memory (target %). Declaring triggers (KEDA scalers) renders a ScaledObject instead of an HPA. |
env | no | Plain environment variables. |
secrets | no | provider (kubernetes aws vault external-secrets), keys mapping ENV_VAR → remote key, storeRef, refreshInterval. See the secrets guide. |
secretFiles | no | File name → {source, mountPath}. |
headers.cors | no | enabled, allowOrigins, allowMethods, allowHeaders, maxAge. |
headers.custom | no | Extra response headers. |
authentication | no | basic (htpasswd secret, enforced in nginx); oidc / jwt / oauth2-proxy enforced at the ingress via platform middleware — projects cannot override those annotations. |
compression | no | gzip (default on), brotli. |
security.profile | no | basic recommended strict internal pci — expands to response headers from the platform library. |
cache.static, cache.html | no | maxAge in compact form: 365d, 12h, 5m, 30s. |
routes | no | Path-based proxying: {path, service, port, authentication}. |
healthCheck | no | path plus probe timings. |
deploy | no | Deployment strategy — see deployment strategies. |
Shorthands
Common cases have compact spellings. They are pure syntax — each expands to the canonical object form before template merging, so a shorthand still deep-merges with whatever the templates set:
| Shorthand (TOML) | Expands to |
|---|---|
ingress = "app.company.com" | [ingress] with host |
build = ["npm ci", "npm run build"] | [build] with enabled = true + commands |
build = false | [build] with enabled = false |
artifact = "dist" | [artifact] with directory |
runtimeConfig = "node dist/main.js" | [runtimeConfig] with command |
security = "strict" | [security] with profile |
healthCheck = "/health" | [healthCheck] with path |
authentication = "basic" | [authentication] enabled with type |
compression = false | [compression] with gzip = false |
cache = {static = "365d", html = "5m"} | per-rule maxAge tables |
deploy = "canary" | [deploy] with strategy |
analysis = ["error-rate"] | named gate references |
The YAML spellings are the same shapes (ingress: app.company.com,
build: [npm ci, npm run build], deploy: canary, …).
Merge order
platform defaults → runtime template → application template
→ environment profile → your pagifier.yaml
Your file always wins. Maps merge deep, lists replace whole, null deletes
a key inherited from a template. Unknown keys are rejected — with a
suggestion when it looks like a typo
(unknown field "artefact" — did you mean "artifact"?).
To see exactly what the merge produced for a running release:
curl -H "Authorization: Bearer $TOKEN" \
https://pagifier.company.com/v1/applications/my-app/environments/prod/releases/RELEASE_ID/config
Validating with CUE
Prefer CUE over JSON Schema? The same contract is published as a CUE schema, with all shorthand forms expressed as disjunctions:
curl -sO https://pagifier.company.com/v1/schema/pagifier.cue
cue vet -d '#Project' pagifier.cue frontend/pagifier.yaml # project files
cue vet -d '#Root' pagifier.cue pagifier.yaml # root manifests
Both formats vet — cue vet reads the same files Pagifier does. It
catches structural problems offline — unknown fields, enum
violations, port ranges, non-ascending canary steps — before anything is
uploaded. The server's POST /v1/validate remains the source of truth: it
additionally resolves templates and enforces cross-field rules (for
example, node requires a runtime command), so run both in CI: cue vet
on every commit, /v1/validate on pull requests.
What Pagifier will never do
Detect frameworks · parse package.json, requirements.txt, or go.mod ·
guess ports · guess build commands · read a Dockerfile (you don't have one) · deploy anything not
explicitly listed in a root manifest.