Skip to content
Latchkey

Render Manifests Before Apply: A CI Pattern

Rendering templated config to a concrete file and diffing it before apply turns silent templating bugs into a visible, reviewable CI step.

Every templater in this cluster shares one CI best practice: render to an artifact, inspect it, then apply. This page is the pattern the individual command pages point back to.

What it does

The pattern separates rendering from applying. A render step (gomplate, ytt, jsonnet, cue export, jinja2, envsubst, and so on) writes a concrete manifest to a file. A diff step compares it against the live cluster or the previous render. Only then does an apply step ship it.

Common usage

bash
# 1. render to an artifact
ytt -f config/ > rendered.yaml
# 2. diff against the live cluster (non-zero exit on drift)
kubectl diff -f rendered.yaml || true
# 3. apply the exact file you diffed
kubectl apply -f rendered.yaml

Why it matters

Risk if you skip itWhat render-then-apply catches
Unset variable renders emptyA blank image: or <no value> is visible in the artifact
Wrong overlay mergedThe diff shows unexpected fields before they hit the cluster
Secret leaked into outputYou can scan the rendered file before it is stored or logged
Tool version driftA pinned renderer + committed artifact makes changes reviewable

In CI

Upload the rendered manifest as a build artifact so a human can review exactly what will be applied, and apply that same file rather than re-rendering at apply time (re-rendering can pick up different env). Keep secrets out of the artifact: render placeholders and inject secrets at deploy time, or scrub the file before upload.

Common errors in CI

"error validating data: ... unknown field" from kubectl apply on a rendered file means the template produced an invalid manifest; the render-then-diff step surfaces it before apply. A rendered file containing a literal <no value>, an empty image: , or a stray $VAR is the fingerprint of a missing template variable. kubectl diff exits 1 on any difference, so wrap it with || true if you only want to log drift.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →