Skip to content

YAML editing patterns

YAML uses spaces for indentation — tabs are a syntax error. The convention in Kubernetes manifests is 2 spaces per level.

# Correct — 2-space indent
spec:
containers:
- name: web
image: nginx:1.27
# Wrong — tab character (invisible, but YAML parsers reject it)
spec:
containers:

YAML auto-types unquoted values. This causes surprises:

ValueYAML interprets as
true, falseBoolean
1.0Float
1Integer
on, off, yes, noBoolean (YAML 1.1)
null, ~Null

When in doubt, quote it:

env:
- name: FEATURE_FLAG
value: "true" # string, not boolean
- name: VERSION
value: "1.0" # string, not float

YAML has two block scalar styles for multi-line content:

data:
config.ini: |
[server]
port=8080
debug=false

Folded block (>) — joins lines with spaces

Section titled “Folded block (>) — joins lines with spaces”
metadata:
annotations:
description: >
This is a long description
that gets folded into a single
line with spaces.

The - suffix strips the trailing newline: |- and >-.

A single YAML file can contain multiple documents separated by ---:

apiVersion: v1
kind: Service
metadata:
name: my-app
spec:
selector:
app: my-app
ports:
- port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: web
image: my-registry/my-app:1.0

kubectl apply -f handles multi-document files natively.

Anchors (&) and aliases (*) let you reuse values without duplication. In a Kubernetes manifest, the anchor must ride on a real field at its first occurrence — a made-up top-level key like common_labels: is an unknown field the API server rejects:

apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels: &labels
app: my-app
team: platform
spec:
replicas: 2
selector:
matchLabels: *labels
template:
metadata:
labels: *labels
spec:
containers:
- name: web
image: my-registry/my-app:1.0

Workload controllers (Deployments, ReplicaSets) and Services find their Pods via label selectors, so the Pod template’s labels must match — and labelling every resource consistently makes selection and monitoring easier. A common minimal set:

metadata:
labels:
app.kubernetes.io/name: my-app
app.kubernetes.io/version: "1.0"
app.kubernetes.io/managed-by: argocd

The app.kubernetes.io/* labels are the recommended convention. At minimum, use app.kubernetes.io/name so Services and monitoring can select your Pods consistently.

Always declare resource requests and limits — on Kestrel, quota is enforced against a shared resource pool across all of your tenant’s namespaces, not per individual namespace:

containers:
- name: web
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
FieldMeaning
requestsGuaranteed minimum — used for scheduling
limitsHard ceiling — container is throttled (CPU) or killed (memory) if exceeded
  1. Forgetting matchLabels — a Deployment’s spec.selector.matchLabels must match the Pod template’s metadata.labels. If they don’t match, the Deployment can’t find its Pods.

  2. Port mismatch — the Service targetPort must match the container’s containerPort. A mismatch means traffic reaches the Pod but hits a closed port.

  3. Image tag latest — never use latest in production manifests. It’s mutable, so you can’t tell which version is running and rollbacks don’t work.

  4. Trailing whitespace in values — value: "my-secret " includes the space; quoting preserves it. The fix is to delete the stray space inside the quotes. The editor settings below (renderWhitespace, files.trimTrailingWhitespace) help you spot and strip trailing whitespace before it ships.

For VS Code or similar editors, install a YAML language server extension with Kubernetes schema support. Recommended settings:

{
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.renderWhitespace": "boundary",
"files.trimTrailingWhitespace": true
}