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:

common_labels: &labels
app: my-app
team: platform
deployment:
metadata:
labels:
<<: *labels
spec:
template:
metadata:
labels:
<<: *labels

Every Kubernetes manifest needs labels that match its selectors. 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 valuesvalue: "my-secret " includes the space. Use |- for block scalars or quote carefully.

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
}