YAML Syntax Guide for Beginners — Complete Walkthrough with Examples
YAML is everywhere in modern development — Kubernetes manifests, GitHub Actions workflows, docker-compose files, Ansible playbooks, and application config. It is designed to be readable, but its whitespace-based syntax has real rules, and breaking them produces confusing errors. This guide walks through YAML from the ground up: key-value pairs, nesting, lists, multi-line strings, quoting, comments, and anchors, ending with a complete worked config file you can use as a reference.
Key-Value Pairs and Nesting
The atom of YAML is key: value — note the mandatory space after the colon. Structure comes from indentation: indent a block under a key to nest it. The two iron rules of indentation:
- Spaces only — never tabs. A single tab character anywhere in the indentation makes the parser fail. Use 2 spaces per level (the universal convention).
- Siblings must align exactly. Keys at the same level need identical indentation, or YAML thinks you started a new (invalid) structure.
app: payment-service # string
port: 8080 # integer
debug: false # boolean
ratio: 0.75 # float
nothing: null # null (also: ~ or just empty)
database: # nested mapping starts here
host: db.internal # 2 spaces in
port: 5432
credentials: # nest deeper with 2 more spaces
user: app_rwLists: Block Style and Inline Flow Style
A list item is a dash plus a space (- ). Lists can hold scalars, mappings, or other lists. For short lists, YAML also accepts JSON-like inline "flow" syntax:
# Block style — one item per line
regions:
- ap-south-1
- eu-west-1
# List of mappings (very common in k8s and CI files)
containers:
- name: web
image: nginx:1.27
- name: sidecar
image: envoy:1.30
# Inline flow style — YAML accepts JSON syntax too
ports: [80, 443, 8080]
labels: { app: web, tier: frontend }Flow style is fine for short scalar lists; switch to block style the moment items get long or nested, or reviewing diffs becomes painful.
Multi-Line Strings: Literal vs Folded
YAML has two block styles for long text, and choosing the wrong one is a classic bug. The pipe | (literal) keeps line breaks exactly as written. The > character (folded) joins lines into one long string, converting each line break into a space:
# Literal (|) — newlines PRESERVED. Use for scripts, certs, SQL. script: | npm ci npm run build npm test # → "npm ci\nnpm run build\nnpm test\n" # Folded (>) — newlines become SPACES. Use for long prose. description: > This service handles UPI payment callbacks and retries failed webhooks up to three times. # → "This service handles UPI payment callbacks and retries failed webhooks up to three times.\n" # Chomping modifiers control the trailing newline: # |- strip the final newline |+ keep all trailing newlines
Rule of thumb: if the line breaks carry meaning (shell commands, certificates, SQL), use the literal pipe. If you only wrapped the text so the file stays readable, use the folded style.
Quoting Rules: When Strings Need Quotes
Most YAML strings need no quotes at all — that is the point of the format. But YAML guesses types from unquoted content, so you must quote anything ambiguous:
- Boolean look-alikes:
yes,no,on,off,true,false - Numbers you want kept as strings: version
"1.10", PIN code"01234" - Values containing
:(colon-space) or starting with#,*,&,?,[,{,!,%,@ - The empty string:
""(an empty value parses as null, not empty string)
answer: no # → boolean false (surprise!) answer: "no" # → string "no" message: 'It''s live' # single quotes: literal, escape ' by doubling path: "C:\\logs\\app" # double quotes: \ escapes work (\n, \t, \\) motto: plain text is fine unquoted # no special chars → no quotes needed
Single quotes are "dumb" (everything literal), double quotes support escape sequences. When in doubt, double-quote — it never changes the meaning of a plain string.
Comments and Anchors
Everything from # to the end of the line is a comment (unless the # is inside a quoted string). Anchors let you define a block once and reuse it — YAML's built-in DRY mechanism:
# Anchor (&) defines, alias (*) reuses, <<: merges into a mapping base: &base cpu: 500m memory: 512Mi web: <<: *base # inherits cpu and memory replicas: 3 worker: <<: *base memory: 1Gi # override one key
Full Worked Example: A Complete Config File
Here is everything above combined into one realistic application config:
# app-config.yml — payment-service
app:
name: payment-service
version: "2.4.10" # quoted — keep as string
debug: false
server:
port: 8080
allowed_hosts:
- api.example.in
- "*.internal" # quoted — starts with *
defaults: &retry_policy
retries: 3
backoff_seconds: 5
upstreams:
- name: upi-gateway
url: "https://gateway.example.com:8443" # contains ://
<<: *retry_policy
- name: sms-provider
url: "https://sms.example.in"
<<: *retry_policy
retries: 5 # override
startup_script: |
./wait-for-db.sh
./migrate.sh
exec node server.js
notes: >
Rotate the gateway API key on the first of every
month and update the secret in the cluster.Not sure how a snippet parses? Paste it into the free YAML to JSON converter — seeing the JSON output instantly reveals whether YAML read your value as a string, number, boolean, or something you did not intend.
Frequently Asked Questions
No. The YAML specification forbids tab characters for indentation — parsers throw an error like "found character that cannot start any token". Always use spaces, with 2 spaces per level being the universal convention. Configure your editor to insert spaces when you press Tab in .yml files.
The pipe (|) is the literal block style: line breaks are preserved exactly as written, ideal for scripts and certificates. The greater-than sign (>) is the folded style: line breaks are folded into spaces, producing one long line — ideal for long prose you wrap for readability in the file.
Most strings need no quotes, but quote values that YAML would misread: boolean look-alikes (yes, no, on, off), numbers you want as strings ("1.10", "01234"), values starting with special characters (*, &, ?, {, [), values containing a colon followed by a space, and anything beginning with # which would otherwise start a comment.