YAML Commands & Tools Cheatsheet
Table of Contents
- YAML Basics
- Data Types
- Advanced Syntax
- YAML Tools
- yq - YAML Processor
- Python YAML
- Ruby YAML
- Go YAML
- Kubernetes YAML
- Docker Compose YAML
- GitHub Actions YAML
- Ansible YAML
- YAML Validation
- YAML Best Practices
- Interview Scenarios
YAML Basics
1. Basic Key-Value Pairs
name: John Doe
age: 30
email: john@example.com2. Nested Objects (Mappings)
person:
name: John Doe
age: 30
contact:
email: john@example.com
phone: 123-456-78903. Lists (Sequences)
# Dash style
fruits:
- apple
- banana
- cherry
# Inline style
numbers: [1, 2, 3, 4, 5]4. Comments
# This is a comment
name: John # Inline comment
# Multi-line comment
# Line 1
# Line 2
age: 305. Strings
# Unquoted
name: John Doe
# Single quoted (literal)
message: 'Hello, World!'
# Double quoted (allows escapes)
path: "C:\\Users\\John"
escaped: "Line 1\nLine 2"6. Multi-line Strings
# Literal block (preserves newlines)
literal: |
Line 1
Line 2
Line 3
# Folded block (folds newlines)
folded: >
This is a long
sentence that will
be folded into one line.
# Strip final newlines (|-)
stripped: |-
Line 1
Line 2
# Keep final newlines (|+)
kept: |+
Line 1
Line 2
Data Types
7. Numbers
integer: 42
float: 3.14
negative: -10
scientific: 1.5e+10
octal: 0o14
hexadecimal: 0xC8. Booleans
enabled: true
disabled: false
yes_value: yes
no_value: no
on_value: on
off_value: off9. Null Values
nothing: null
tilde: ~
empty:10. Dates and Timestamps
date: 2026-02-15
datetime: 2026-02-15T10:30:00Z
timestamp: 2026-02-15 10:30:0011. Lists of Objects
users:
- name: John
age: 30
email: john@example.com
- name: Jane
age: 25
email: jane@example.com12. Mixed Lists
mixed:
- string
- 42
- true
- null
- name: nested object
value: 123Advanced Syntax
13. Anchors and Aliases (Reuse)
defaults: &defaults
timeout: 30
retries: 3
development:
<<: *defaults
host: dev.example.com
production:
<<: *defaults
host: prod.example.com
timeout: 60 # Override14. Merge Keys
base: &base
name: Base
version: 1.0
app1:
<<: *base
port: 8080
app2:
<<: *base
port: 808115. Multiple Anchors
auth: &auth
username: admin
password: secret
database: &db
host: localhost
port: 5432
app:
<<: [*auth, *db]
name: MyApp16. Explicit Types
# Force string
version: !!str 1.0
numbers: !!str 123
# Force integer
count: !!int "42"
# Force float
price: !!float 99
# Binary data
data: !!binary |
R0lGODlhDAAMAIQAAP//9/X17. Multi-line Keys
? - key1
- key2
: value
# Or
? |
This is a
multi-line key
: value18. Sets
# Unique values (rarely used)
colors: !!set
? red
? green
? blue19. Ordered Maps
# Preserves order (rarely used)
ordered: !!omap
- first: 1
- second: 2
- third: 320. Environment Variable Style
database:
host: ${DB_HOST}
port: ${DB_PORT:-5432} # With default
name: ${DB_NAME}YAML Tools
21. Install yq (YAML Processor)
# macOS
brew install yq
# Linux
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
chmod +x yq_linux_amd64
sudo mv yq_linux_amd64 /usr/local/bin/yq
# Via Go
go install github.com/mikefarah/yq/v4@latest22. yamllint (Linter)
pip install yamllint
yamllint file.yaml
yamllint -d relaxed file.yaml23. Online Validators
- https://www.yamllint.com/
- https://onlineyamltools.com/validate-yaml
- https://jsonformatter.org/yaml-validator
yq - YAML Processor
24. Basic yq Usage
# Pretty print
yq '.' file.yaml
# Evaluate expression
yq '.name' file.yaml
# Multiple files
yq '.' file1.yaml file2.yaml
# In-place edit
yq -i '.name = "John"' file.yaml25. Read Values
# Single value
yq '.name' config.yaml
# Nested value
yq '.database.host' config.yaml
# Array element
yq '.users[0].name' config.yaml
# All array elements
yq '.users[].name' config.yaml26. Write/Update Values
# Set value
yq '.name = "John"' file.yaml
# Set nested value
yq '.database.host = "localhost"' file.yaml
# Add to array
yq '.items += "new-item"' file.yaml
# Delete key
yq 'del(.obsolete)' file.yaml27. Filter and Select
# Filter array
yq '.users[] | select(.age > 30)' file.yaml
# Multiple conditions
yq '.users[] | select(.age > 30 and .active == true)' file.yaml28. Convert YAML to JSON
yq -o json '.' file.yaml
# Pretty JSON
yq -o json -I 2 '.' file.yaml29. Convert JSON to YAML
yq -p json '.' file.json
# Or with jq
jq -r '.' file.json | yq -P '.'30. Merge YAML Files
# Merge two files
yq ea '. as $item ireduce ({}; . * $item)' file1.yaml file2.yaml
# Merge arrays
yq ea '[.]' file1.yaml file2.yaml
# Merge specific keys
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' file1.yaml file2.yaml31. Extract Specific Fields
# Create new structure
yq '{name: .user.name, email: .user.email}' file.yaml
# Multiple items
yq '.users[] | {name, email}' file.yaml32. Loop Through Items
# With bash
yq '.users[].name' file.yaml | while read name; do
echo "User: $name"
done33. Sort Arrays
# Sort by field
yq '.users |= sort_by(.age)' file.yaml
# Reverse sort
yq '.users |= sort_by(.age) | reverse' file.yaml34. Length/Count
# Array length
yq '.users | length' file.yaml
# String length
yq '.name | length' file.yaml35. Keys
# Get all keys
yq 'keys' file.yaml
# Nested keys
yq '.database | keys' file.yaml36. Conditional Updates
# Update if condition met
yq '(.users[] | select(.name == "John") | .age) = 31' file.yaml
# Add field conditionally
yq '.users[] |= . + (if .age > 30 then {"senior": true} else {} end)' file.yaml37. Array Operations
# Map array
yq '.users |= map(. + {"active": true})' file.yaml
# Filter and transform
yq '.users |= map(select(.age > 25) | {name, email})' file.yaml38. String Operations
# Concatenate
yq '.fullname = .firstname + " " + .lastname' file.yaml
# Uppercase/Lowercase
yq '.name |= upcase' file.yaml
yq '.name |= downcase' file.yaml
# Replace
yq '.message |= sub("old", "new")' file.yaml39. Math Operations
# Add
yq '.age += 1' file.yaml
# Multiply
yq '.price *= 1.1' file.yaml
# Calculate
yq '.total = .price * .quantity' file.yaml40. Environment Variables
# Use env variable
export USERNAME="john"
yq '.user.name = env(USERNAME)' file.yaml
# With default
yq '.port = (env(PORT) // 8080)' file.yamlPython YAML
41. Install PyYAML
pip install pyyaml42. Load YAML
import yaml
# From string
yaml_string = """
name: John
age: 30
"""
data = yaml.safe_load(yaml_string)
# From file
with open('config.yaml', 'r') as file:
data = yaml.safe_load(file)
print(data['name'])43. Load Multiple Documents
# file.yaml
---
document: first
---
document: secondwith open('file.yaml', 'r') as file:
documents = yaml.safe_load_all(file)
for doc in documents:
print(doc)44. Dump YAML
import yaml
data = {
'name': 'John',
'age': 30,
'emails': ['john@example.com']
}
# To string
yaml_string = yaml.dump(data)
# Pretty print
yaml_string = yaml.dump(data, default_flow_style=False)
# To file
with open('output.yaml', 'w') as file:
yaml.dump(data, file, default_flow_style=False)45. Custom Constructors
import yaml
def person_constructor(loader, node):
values = loader.construct_mapping(node)
return f"{values['first']} {values['last']}"
yaml.add_constructor('!person', person_constructor)
yaml_string = """
user: !person
first: John
last: Doe
"""
data = yaml.safe_load(yaml_string)46. Preserve Order
from collections import OrderedDict
import yaml
def ordered_load(stream):
class OrderedLoader(yaml.SafeLoader):
pass
def construct_mapping(loader, node):
return OrderedDict(loader.construct_pairs(node))
OrderedLoader.add_constructor(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
construct_mapping
)
return yaml.load(stream, OrderedLoader)Ruby YAML
47. Load YAML (Ruby)
require 'yaml'
# From file
data = YAML.load_file('config.yaml')
# From string
yaml_string = <<~YAML
name: John
age: 30
YAML
data = YAML.load(yaml_string)
puts data['name']48. Dump YAML (Ruby)
require 'yaml'
data = {
'name' => 'John',
'age' => 30
}
# To string
yaml_string = data.to_yaml
# To file
File.open('output.yaml', 'w') { |f| f.write(data.to_yaml) }Go YAML
49. Load YAML (Go)
package main
import (
"gopkg.in/yaml.v3"
"io/ioutil"
"log"
)
type Config struct {
Name string `yaml:"name"`
Age int `yaml:"age"`
Email string `yaml:"email"`
}
func main() {
data, err := ioutil.ReadFile("config.yaml")
if err != nil {
log.Fatal(err)
}
var config Config
err = yaml.Unmarshal(data, &config)
if err != nil {
log.Fatal(err)
}
log.Printf("Name: %s", config.Name)
}50. Dump YAML (Go)
package main
import (
"gopkg.in/yaml.v3"
"io/ioutil"
"log"
)
type Config struct {
Name string `yaml:"name"`
Age int `yaml:"age"`
}
func main() {
config := Config{
Name: "John",
Age: 30,
}
data, err := yaml.Marshal(&config)
if err != nil {
log.Fatal(err)
}
err = ioutil.WriteFile("output.yaml", data, 0644)
if err != nil {
log.Fatal(err)
}
}Kubernetes YAML
51. Pod Definition
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
env:
- name: ENV_VAR
value: "value"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"52. Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 8053. Service
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer54. ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
database.host: "localhost"
database.port: "5432"
app.properties: |
key1=value1
key2=value255. Secret
apiVersion: v1
kind: Secret
metadata:
name: app-secret
type: Opaque
data:
username: YWRtaW4= # base64 encoded
password: cGFzc3dvcmQ=
stringData:
email: admin@example.com # Plain textDocker Compose YAML
56. Basic Docker Compose
version: '3.8'
services:
web:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
environment:
- NGINX_HOST=localhost
- NGINX_PORT=80
networks:
- webnet
database:
image: postgres:14
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db-data:/var/lib/postgresql/data
networks:
- webnet
networks:
webnet:
volumes:
db-data:57. Docker Compose with Build
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
- NODE_ENV=production
ports:
- "3000:3000"
depends_on:
- redis
- postgres
environment:
- DATABASE_URL=postgres://user:pass@postgres:5432/db
- REDIS_URL=redis://redis:6379
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
postgres:
image: postgres:14-alpine
environment:
POSTGRES_DB: ${DB_NAME:-mydb}
POSTGRES_USER: ${DB_USER:-user}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres-data:/var/lib/postgresql/data
volumes:
redis-data:
postgres-data:58. Health Checks
services:
web:
image: nginx
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40sGitHub Actions YAML
59. Basic Workflow
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build60. Matrix Strategy
name: Matrix Test
on: [push]
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: ['lts/*', 'current']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm test61. Reusable Workflows
name: Reusable Workflow
on:
workflow_call:
inputs:
environment:
required: true
type: string
secrets:
token:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v4
- name: Deploy
run: ./deploy.sh
env:
TOKEN: ${{ secrets.token }}Ansible YAML
62. Ansible Playbook
---
- name: Configure web servers
hosts: webservers
become: yes
vars:
http_port: 80
domain: example.com
tasks:
- name: Install nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Start nginx service
service:
name: nginx
state: started
enabled: yes
- name: Copy config file
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: restart nginx
handlers:
- name: restart nginx
service:
name: nginx
state: restarted63. Ansible Inventory
all:
children:
webservers:
hosts:
web1:
ansible_host: 192.168.1.10
web2:
ansible_host: 192.168.1.11
vars:
ansible_user: ubuntu
databases:
hosts:
db1:
ansible_host: 192.168.1.20
db2:
ansible_host: 192.168.1.21
vars:
ansible_user: admin64. Ansible Roles
# playbook.yml
---
- hosts: webservers
roles:
- common
- nginx
- { role: database, db_name: myapp }YAML Validation
65. Validate with yamllint
# Basic validation
yamllint file.yaml
# Custom config
yamllint -d '{extends: default, rules: {line-length: {max: 120}}}' file.yaml
# Configuration file (.yamllint)
cat > .yamllint << 'EOF'
extends: default
rules:
line-length:
max: 120
indentation:
spaces: 2
comments:
min-spaces-from-content: 1
EOF
yamllint .66. Validate with Python
import yaml
import sys
try:
with open('config.yaml', 'r') as file:
data = yaml.safe_load(file)
print("Valid YAML")
except yaml.YAMLError as e:
print(f"Invalid YAML: {e}")
sys.exit(1)67. Validate Kubernetes YAML
# Dry run
kubectl apply -f deployment.yaml --dry-run=client
# Validate
kubectl apply -f deployment.yaml --validate=true --dry-run=server
# Using kubeval
kubeval deployment.yaml
# Using kustomize
kustomize build . | kubectl apply --dry-run=client -f -YAML Best Practices
68. Indentation
# Use 2 spaces (recommended)
parent:
child:
grandchild: value
# Never use tabs
# ❌ Bad
parent:
→ child: value
# ✅ Good
parent:
child: value69. Quotes
# When to use quotes
numeric_string: "123" # Force string
special_chars: "yes@no" # Contains special chars
starts_with_space: " text" # Starts with space
colons_in_value: "key: value" # Contains colon
# When not needed
simple_string: hello
number: 123
boolean: true70. Long Lines
# Bad - too long
description: "This is a very long description that exceeds the recommended line length and makes the file hard to read"
# Good - use folded style
description: >
This is a very long description
that is split across multiple lines
for better readability
# Or literal style
script: |
#!/bin/bash
echo "Line 1"
echo "Line 2"71. Consistent Naming
# Choose one style and stick with it
# snake_case (Python)
database_host: localhost
api_key: secret
# camelCase (JavaScript)
databaseHost: localhost
apiKey: secret
# kebab-case (YAML/Kubernetes)
database-host: localhost
api-key: secret72. Comments
# Section comment explaining the purpose
database:
# Host configuration
host: localhost # Can override with DB_HOST
port: 5432 # Default PostgreSQL port
# Authentication
username: admin
password: secret # Store in vault for production73. Anchors Best Practices
# Bad - overusing anchors
item1: &anchor1
<<: *base
<<: *auth
<<: *network
value: 1
# Good - use anchors for repeated configurations
defaults: &defaults
timeout: 30
retries: 3
service1:
<<: *defaults
name: api
service2:
<<: *defaults
name: workerInterview Scenarios
Scenario 1: Parse Multi-Environment Config
Question: Extract database config for specific environment
# config.yaml
cat > config.yaml << 'EOF'
environments:
development:
database:
host: localhost
port: 5432
production:
database:
host: prod-db.example.com
port: 5432
EOF
# Extract production database config
yq '.environments.production.database' config.yamlScenario 2: Update Kubernetes Image
Question: Update container image in deployment
yq '.spec.template.spec.containers[0].image = "nginx:1.22"' deployment.yaml
# Update in-place
yq -i '.spec.template.spec.containers[0].image = "nginx:1.22"' deployment.yaml
# Update all containers
yq -i '.spec.template.spec.containers[].image = "nginx:1.22"' deployment.yamlScenario 3: Merge Environment-Specific Configs
Question: Merge base and environment-specific configurations
# base.yaml
cat > base.yaml << 'EOF'
app:
name: myapp
timeout: 30
EOF
# prod.yaml
cat > prod.yaml << 'EOF'
app:
host: prod.example.com
replicas: 5
EOF
# Merge
yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' base.yaml prod.yamlScenario 4: Extract All Container Images
Question: List all container images from Kubernetes manifests
# From single file
yq '.spec.template.spec.containers[].image' deployment.yaml
# From multiple files
yq '.spec.template.spec.containers[].image' k8s/*.yaml | sort -u
# From complex structure
find . -name "*.yaml" -exec yq '.. | .image? | select(.)' {} \; | sort -uScenario 5: Validate Required Fields
Question: Check if all deployments have resource limits
yq '
.spec.template.spec.containers[] |
select(.resources.limits.memory == null or .resources.limits.cpu == null) |
"Missing limits for: " + .name
' deployment.yamlScenario 6: Generate ConfigMap from Files
Question: Create Kubernetes ConfigMap from multiple files
#!/bin/bash
echo "apiVersion: v1"
echo "kind: ConfigMap"
echo "metadata:"
echo " name: app-config"
echo "data:"
for file in config/*.properties; do
key=$(basename "$file")
echo " $key: |"
sed 's/^/ /' "$file"
doneScenario 7: Convert Between Formats
Question: Convert Docker Compose to Kubernetes
# Using kompose
kompose convert -f docker-compose.yaml
# Manual conversion with yq
# Extract service name and image
yq '.services | to_entries | .[] | {
"name": .key,
"image": .value.image
}' docker-compose.yamlScenario 8: Bulk Update Labels
Question: Add labels to all Kubernetes resources
# Add label to all resources
for file in k8s/*.yaml; do
yq -i '.metadata.labels.environment = "production"' "$file"
done
# Add label only to deployments
yq -i '
select(.kind == "Deployment") |
.metadata.labels.environment = "production"
' k8s/*.yamlScenario 9: Find Resources by Label
Question: Find all services with specific label
yq 'select(.kind == "Service" and .metadata.labels.app == "nginx")' k8s/*.yaml
# Extract just the names
yq '
select(.kind == "Service" and .metadata.labels.app == "nginx") |
.metadata.name
' k8s/*.yamlScenario 10: Template Substitution
Question: Replace placeholders with environment variables
#!/bin/bash
export APP_NAME="myapp"
export APP_VERSION="1.0.0"
export REPLICAS="3"
# Using envsubst
envsubst < template.yaml > output.yaml
# Using yq with env variables
yq '
.metadata.name = env(APP_NAME) |
.spec.replicas = env(REPLICAS) |
.spec.template.spec.containers[0].image = env(APP_NAME) + ":" + env(APP_VERSION)
' template.yaml > output.yamlScenario 11: Split Multi-Document YAML
Question: Split multi-document YAML into separate files
#!/bin/bash
# all.yaml contains multiple documents
csplit -s -f resource- all.yaml '/^---$/' '{*}'
# Rename based on content
for file in resource-*; do
kind=$(yq '.kind' "$file")
name=$(yq '.metadata.name' "$file")
mv "$file" "${kind}-${name}.yaml"
doneScenario 12: Validate CI/CD Pipeline
Question: Check GitHub Actions workflow for deprecated actions
yq '
.jobs.*.steps[] |
select(.uses) |
select(.uses | test("@v1$")) |
"Deprecated action: " + .uses
' .github/workflows/*.ymlScenario 13: Generate Documentation
Question: Extract API endpoints from OpenAPI YAML
yq '
.paths | to_entries | .[] |
"Endpoint: " + .key + "\n" +
" Methods: " + (.value | keys | join(", "))
' openapi.yamlScenario 14: Compare Configurations
Question: Find differences between two YAML configs
# Using diff with sorted YAML
diff <(yq -P 'sort_keys(..)' file1.yaml) <(yq -P 'sort_keys(..)' file2.yaml)
# Using yq to show specific changes
yq '
load("file1.yaml") as $old |
load("file2.yaml") as $new |
($new | keys) - ($old | keys) as $added |
($old | keys) - ($new | keys) as $removed |
{
"added": $added,
"removed": $removed
}
'Scenario 15: Optimize Docker Compose
Question: Remove unused networks and volumes
# Find services that use specific network
yq '.services.* | select(.networks != null) | .networks[]' docker-compose.yaml | sort -u
# Clean up unused networks
used_networks=$(yq '.services.*.networks[]' docker-compose.yaml | sort -u)
yq -i "
.networks = (.networks | with_entries(
select(.key as \$k | \"$used_networks\" | contains(\$k))
))
" docker-compose.yamlAdvanced Patterns
76. Schema Validation
# schema.yaml
$schema: http://json-schema.org/draft-07/schema#
type: object
required:
- apiVersion
- kind
- metadata
properties:
apiVersion:
type: string
kind:
type: string
metadata:
type: object
required:
- name77. Custom Tags
# Define custom tag
database: !secret
password: encrypted_value
# Process in Python
import yaml
def secret_constructor(loader, node):
value = loader.construct_mapping(node)
# Decrypt password
return value
yaml.add_constructor('!secret', secret_constructor)78. Conditional Include
# Include file conditionally (using yq)
environments:
<<: *base
production:
$if: env(ENVIRONMENT) == "production"
replicas: 5Quick Reference
YAML Syntax
Key-value: key: value
Nested: parent:
child: value
List: - item1
- item2
Inline list: [item1, item2]
Inline object: {key1: value1, key2: value2}
Multi-line |: Preserves newlines
Multi-line >: Folds newlines
Comment: # This is a comment
Anchor: &name and *name
Merge: <<: *anchorCommon Tools
yq YAML processor
yamllint Linter
kubectl Kubernetes validation
kompose Docker Compose to K8s
jsonnet Advanced templatingFile Extensions
.yaml Primary extension
.yml Alternative extension