Cheatsheets

YAML

YAML

YAML (YAML Ain't Markup Language) is a human-friendly data serialization language commonly used for configuration files, data exchange, and infrastructure-as-code. It emphasizes readability and uses indentation to structure data.

6 Categories 18 Sections 36 Examples
YAML Configuration Data Serialization Syntax Indentation Keys Values Anchors Aliases

Getting Started

Fundamental YAML concepts and basic syntax for beginners.

Basic Syntax

YAML fundamentals including comments, key-value pairs, and indentation rules.

Basic key-value pair

Simple key-value pairs are the foundation of YAML syntax. Keys are followed by a colon and space, then the value.

Code
name: John Doe
age: 30
city: New York
Execution
python -c "import yaml; print(yaml.safe_load(open('config.yaml')))"
Output
{'name': 'John Doe', 'age': 30, 'city': 'New York'}
  • Indentation is crucial in YAML; use spaces, not tabs.
  • Keys and values are separated by a colon and at least one space.

Comments in YAML

Comments begin with

Code
# This is a comment
name: John Doe # inline comment
age: 30
# Another comment
city: New York
Execution
python -c "import yaml; print(yaml.safe_load(open('config.yaml')))"
Output
{'name': 'John Doe', 'age': 30, 'city': 'New York'}
  • Comments can be placed on their own line or at the end of a line.
  • Use comments to document configuration intent and choices.

Data Types

Understanding YAML data types including strings, numbers, booleans, and null values.

Different data types

YAML automatically infers data types based on content. Explicitly quote strings to avoid type inference issues.

Code
string: "Hello World"
integer: 42
float: 3.14
boolean_true: true
boolean_false: false
null_value: null
Execution
python -c "import yaml; print(yaml.safe_load(open('types.yaml')))"
Output
{'string': 'Hello World', 'integer': 42, 'float': 3.14, 'boolean_true': True, 'boolean_false': False, 'null_value': None}
  • YAML supports strings, integers, floats, booleans, and null values.
  • Unquoted strings like 'true' and 'false' are parsed as booleans.

Quoted strings

Quoting forces YAML to treat values as strings. Single and double quotes work similarly in YAML.

Code
single_quoted: 'hello'
double_quoted: "world"
unquoted: plain text
number_as_string: '42'
Execution
python -c "import yaml; print(yaml.safe_load(open('quotes.yaml')))"
Output
{'single_quoted': 'hello', 'double_quoted': 'world', 'unquoted': 'plain text', 'number_as_string': '42'}
  • Quote numbers if you want them treated as strings.
  • Unquoted strings are converted based on content interpretation.

Comments

How to use comments effectively in YAML files for documentation and clarity.

Comment placement and styles

Comments provide documentation without affecting the parsed data structure.

Code
# Top-level comment explaining the file
# This configuration defines application settings
app:
name: MyApp # The application name
version: 1.0 # Version number
# Debug mode settings
debug: false
Execution
python -c "import yaml; print(yaml.safe_load(open('comments.yaml')))"
Output
{'app': {'name': 'MyApp', 'version': 1.0, 'debug': False}}
  • Comments are ignored during parsing and do not appear in the output.
  • Use comments to explain the purpose of configuration values.

Documenting complex structures

Comments help explain the purpose of configuration sections and individual settings.

Code
# Database connection settings
database:
# Connection string for PostgreSQL
host: localhost
port: 5432 # Standard PostgreSQL port
# Credentials for authentication
username: admin
password: secret
Execution
python -c "import yaml; print(yaml.safe_load(open('db_config.yaml')))"
Output
{'database': {'host': 'localhost', 'port': 5432, 'username': 'admin', 'password': 'secret'}}
  • Group related comments with the sections they document.
  • Keep comments concise and focused on the 'why', not the 'what'.

Data Structures

Understanding dictionaries, lists, and mixed nested structures in YAML.

Dictionaries

Creating and using dictionaries (key-value mappings) in YAML.

Simple dictionary

A dictionary is created by indenting key-value pairs under a parent key.

Code
person:
name: John Doe
age: 30
email: john@example.com
Execution
python -c "import yaml; print(yaml.safe_load(open('person.yaml')))"
Output
{'person': {'name': 'John Doe', 'age': 30, 'email': 'john@example.com'}}
  • Use consistent indentation to define dictionary membership.
  • Each key-value pair must have the same indentation level.

Nested dictionaries

Dictionaries can be nested multiple levels deep by continuing to indent.

Code
user:
profile:
name: Alice
contact:
email: alice@example.com
phone: "555-1234"
settings:
theme: dark
notifications: true
Execution
python -c "import yaml; print(yaml.safe_load(open('nested.yaml')))"
Output
{'user': {'profile': {'name': 'Alice', 'contact': {'email': 'alice@example.com', 'phone': '555-1234'}}, 'settings': {'theme': 'dark', 'notifications': True}}}
  • Each level of nesting increases indentation by 2 spaces.
  • Maintain consistent indentation to correctly represent hierarchy.

Lists

Creating and using lists (arrays) in YAML.

Simple list

Lists are created using dashes (-) followed by a space, with each item on a new line.

Code
fruits:
- apple
- banana
- orange
- grape
Execution
python -c "import yaml; print(yaml.safe_load(open('fruits.yaml')))"
Output
{'fruits': ['apple', 'banana', 'orange', 'grape']}
  • Each list item starts with a dash and a space.
  • All list items must have the same indentation level.

Nested lists

Lists can contain other lists, creating multi-dimensional structures.

Code
matrix:
- - 1
- 2
- 3
- - 4
- 5
- 6
- - 7
- 8
- 9
Execution
python -c "import yaml; print(yaml.safe_load(open('matrix.yaml')))"
Output
{'matrix': [[1, 2, 3], [4, 5, 6], [7, 8, 9]]}
  • Nested lists use additional indentation and dashes.
  • Readability decreases with deep nesting; simplify when possible.

Mixed Structures

Combining dictionaries and lists in complex nested structures.

List of dictionaries

Each list item is a dictionary with multiple key-value pairs. The dash precedes the first key of each dictionary.

Code
employees:
- name: Alice
department: Engineering
salary: 80000
- name: Bob
department: Sales
salary: 60000
- name: Carol
department: Engineering
salary: 85000
Execution
python -c "import yaml; print(yaml.safe_load(open('employees.yaml')))"
Output
{'employees': [{'name': 'Alice', 'department': 'Engineering', 'salary': 80000}, {'name': 'Bob', 'department': 'Sales', 'salary': 60000}, {'name': 'Carol', 'department': 'Engineering', 'salary': 85000}]}
  • The dash and first key are at the same indentation level.
  • Subsequent keys are indented to align under the first key.

Dictionary with list values

Dictionary values can be lists. The list starts on the next indented line with dashes.

Code
project:
name: MyProject
team:
- Alice
- Bob
- Carol
tools:
- Python
- Docker
- Kubernetes
Execution
python -c "import yaml; print(yaml.safe_load(open('project.yaml')))"
Output
{'project': {'name': 'MyProject', 'team': ['Alice', 'Bob', 'Carol'], 'tools': ['Python', 'Docker', 'Kubernetes']}}
  • List values are indented further than the parent key.
  • Each list item is indented consistently.

Advanced Syntax

Exploring advanced YAML features like multiline strings and special characters.

Multiline Strings

Handling strings that span multiple lines using block scalars.

Literal block scalar

The pipe (|) operator preserves newlines and formatting within the string.

Code
description: |
This is a literal block scalar.
Newlines are preserved exactly as written.
Each line becomes a separate line in the string.
Execution
python -c "import yaml; print(repr(yaml.safe_load(open('literal.yaml'))['description']))"
Output
'This is a literal block scalar.\nNewlines are preserved exactly as written.\nEach line becomes a separate line in the string.\n'
  • Literal blocks preserve all whitespace and newlines.
  • Content must be indented below the pipe character.

Folded block scalar

The greater-than (>) operator folds lines into a single line, preserving paragraph breaks.

Code
summary: >
This is a folded block scalar.
Line breaks are converted to spaces.
Paragraphs are separated by blank lines.
Execution
python -c "import yaml; print(repr(yaml.safe_load(open('folded.yaml'))['summary']))"
Output
'This is a folded block scalar. Line breaks are converted to spaces. Paragraphs are separated by blank lines.\n'
  • Folded blocks join lines with spaces.
  • Blank lines create paragraph separations.

Special Strings

Handling quoted strings, escape sequences, and special characters.

Quoted strings with escapes

Double and single quotes allow special characters and escape sequences within strings.

Code
single: 'It''s a string'
double: "Line 1\nLine 2"
path: "C:\\Users\\name\\file.txt"
colon: "key: value"
Execution
python -c "import yaml; d = yaml.safe_load(open('quoted.yaml')); print({k: repr(v) for k, v in d.items()})"
Output
{'single': "It's a string", 'double': 'Line 1\nLine 2', 'path': 'C:\\Users\\name\\file.txt', 'colon': 'key: value'}
  • Single quotes preserve most escapes literally; double quotes interpret them.
  • Escape special characters like colons by quoting the entire string.

Escape sequences

Escape sequences in double-quoted strings are interpreted as special characters.

Code
newline: "Line 1\nLine 2"
tab: "Column1\tColumn2"
quote: "She said \"hello\""
backslash: "Path: C:\\\\folder"
Execution
python -c "import yaml; d = yaml.safe_load(open('escapes.yaml')); print({k: repr(v) for k, v in d.items()})"
Output
{'newline': 'Line 1\nLine 2', 'tab': 'Column1\tColumn2', 'quote': 'She said "hello"', 'backslash': 'Path: C:\\folder'}
  • Common escapes include \\n (newline), \\t (tab), \\\\ (backslash).
  • Single quotes do not interpret most escape sequences.

Anchors and Aliases

Creating references to reuse content within a YAML file.

Basic anchor and alias

Anchors (&) mark content for reference, and aliases (*) reuse that content with the merge key (<<).

Code
defaults: &default_settings
timeout: 30
retries: 3
debug: false
api_config:
<<: *default_settings
endpoint: https://api.example.com
Execution
python -c "import yaml; print(yaml.safe_load(open('anchor.yaml')))"
Output
{'defaults': {'timeout': 30, 'retries': 3, 'debug': False}, 'api_config': {'timeout': 30, 'retries': 3, 'debug': False, 'endpoint': 'https://api.example.com'}}
  • Anchors are defined with & followed by a name.
  • Aliases reference anchors with * followed by the same name.

Multiple alias usage

The same anchor can be referenced multiple times by different aliases throughout the file.

Code
common: &common_values
version: 1.0
author: 'Mohammad Abu Mattar'
service1:
<<: *common_values
name: Service One
service2:
<<: *common_values
name: Service Two
Execution
python -c "import yaml; print(yaml.safe_load(open('multi_alias.yaml')))"
Output
{'common': {'version': 1.0, 'author': 'Admin'}, 'service1': {'version': 1.0, 'author': 'Admin', 'name': 'Service One'}, 'service2': {'version': 1.0, 'author': 'Admin', 'name': 'Service Two'}}
  • Each alias creates an independent copy of the anchored content.
  • Anchors must be defined before they are used with aliases.

Advanced Features

Exploring anchors, aliases, and merge keys for configuration inheritance.

Anchors

Defining and naming anchors for content reuse.

Defining anchors

Anchors are defined using & followed by a name, marking content for later reference.

Code
default_env: &default_env
LOG_LEVEL: info
DEBUG: false
db_config: &db_defaults
host: localhost
port: 5432
pool_size: 10
Execution
python -c "import yaml; print(yaml.safe_load(open('anchors.yaml')))"
Output
{'default_env': {'LOG_LEVEL': 'info', 'DEBUG': False}, 'db_config': {'host': 'localhost', 'port': 5432, 'pool_size': 10}}
  • Anchor names should be descriptive and follow naming conventions.
  • Anchors mark the exact structure they're placed on (dictionaries or values).

Named anchors for inheritance

Named anchors allow defining base configurations that can be inherited by multiple services.

Code
base_service: &base
image: ubuntu:20.04
restart_policy: always
environment:
APP_ENV: production
web_service:
<<: *base
ports:
- 80:8080
Execution
python -c "import yaml; print(yaml.safe_load(open('base.yaml')))"
Output
{'base_service': {'image': 'ubuntu:20.04', 'restart_policy': 'always', 'environment': {'APP_ENV': 'production'}}, 'web_service': {'image': 'ubuntu:20.04', 'restart_policy': 'always', 'environment': {'APP_ENV': 'production'}, 'ports': ['80:8080']}}
  • Anchors are local to the file and cannot be referenced across files.
  • The merge key (<<) combines anchored content with additional properties.

Aliases

Using aliases to reference anchored content.

Using aliases

Aliases (asterisk) reference anchored content, creating independent copies in each location.

Code
shared_config: &shared
timeout: 30
retries: 3
api_service:
name: API
config: *shared
worker_service:
name: Worker
config: *shared
Execution
python -c "import yaml; d = yaml.safe_load(open('alias_usage.yaml')); import json; print(json.dumps(d, indent=2))"
Output
{
"shared_config": {"timeout": 30, "retries": 3},
"api_service": {"name": "API", "config": {"timeout": 30, "retries": 3}},
"worker_service": {"name": "Worker", "config": {"timeout": 30, "retries": 3}}
}
  • An alias creates a new copy of the anchored content, not a reference.
  • Aliases must refer to previously defined anchors.

Multiple references to same anchor

A single anchor can be referenced multiple times throughout the file via separate aliases.

Code
defaults: &defaults
cache: redis
cache_ttl: 3600
app_settings:
cache_settings: *defaults
service_settings:
cache_settings: *defaults
worker_settings:
cache_settings: *defaults
Execution
python -c "import yaml; print(yaml.safe_load(open('multi_ref.yaml')))"
Output
{'defaults': {'cache': 'redis', 'cache_ttl': 3600}, 'app_settings': {'cache_settings': {'cache': 'redis', 'cache_ttl': 3600}}, 'service_settings': {'cache_settings': {'cache': 'redis', 'cache_ttl': 3600}}, 'worker_settings': {'cache_settings': {'cache': 'redis', 'cache_ttl': 3600}}}
  • Each alias reference creates an independent copy of the content.
  • Modifying one copy does not affect others.

Merge Keys

Using the merge key (<<) to inherit and extend configurations.

Using merge key for inheritance

The merge key (<<) incorporates anchored content and allows overriding specific values.

Code
defaults: &defaults
timeout: 30
retries: 3
debug: false
production:
<<: *defaults
environment: production
debug: false
staging:
<<: *defaults
environment: staging
debug: true
Execution
python -c "import yaml; print(yaml.safe_load(open('merge_inherit.yaml')))"
Output
{'defaults': {'timeout': 30, 'retries': 3, 'debug': False}, 'production': {'timeout': 30, 'retries': 3, 'debug': False, 'environment': 'production'}, 'staging': {'timeout': 30, 'retries': 3, 'debug': True, 'environment': 'staging'}}
  • The merge key must be used with an alias.
  • Values defined after the merge key override inherited values.

Multiple merge keys

Multiple anchors can be merged using a list syntax [*anchor1, *anchor2].

Code
base: &base
port: 8080
timeout: 30
logging: &logging
log_level: info
log_file: /var/log/app.log
service:
<<: [*base, *logging]
name: MyService
replicas: 3
Execution
python -c "import yaml; print(yaml.safe_load(open('multi_merge.yaml')))"
Output
{'base': {'port': 8080, 'timeout': 30}, 'logging': {'log_level': 'info', 'log_file': '/var/log/app.log'}, 'service': {'port': 8080, 'timeout': 30, 'log_level': 'info', 'log_file': '/var/log/app.log', 'name': 'MyService', 'replicas': 3}}
  • When multiple anchors are merged, keys from later anchors override earlier ones if there are conflicts.

Collections and Nesting

Deep nesting, complex hierarchies, and organizing multi-level structures.

Nested Dictionaries

Creating and managing deeply nested dictionary structures.

Simple nested dictionaries

Nested dictionaries use increasing indentation to show hierarchical relationships.

Code
company:
name: TechCorp
location: New York
departments:
engineering:
team_lead: Alice
members: 10
sales:
team_lead: Bob
members: 5
Execution
python -c "import yaml; d = yaml.safe_load(open('nested_dict.yaml')); print(d['company']['departments']['engineering'])"
Output
{'team_lead': 'Alice', 'members': 10}
  • Each indentation level represents one level of nesting.
  • Maintain consistent indentation (typically 2 spaces per level).

Deeply nested structure

Multiple levels of nesting create a clear hierarchy for complex configurations.

Code
system:
server:
production:
database:
primary:
host: prod-db-1.example.com
port: 5432
credentials:
username: prod_user
password: secret123
Execution
python -c "import yaml; d = yaml.safe_load(open('deep_nest.yaml')); print(d['system']['server']['production']['database']['primary']['credentials'])"
Output
{'username': 'prod_user', 'password': 'secret123'}
  • Keep nesting reasonable (3-4 levels) for readability.
  • Consider flattening deeply nested structures using descriptive keys.

Nested Lists

Creating and managing lists containing other lists.

List of lists

Nested lists use additional dashes and indentation to represent multi-dimensional arrays.

Code
grid:
- - North
- South
- East
- West
- - Up
- Down
- Left
- Right
Execution
python -c "import yaml; print(yaml.safe_load(open('grid.yaml')))"
Output
{'grid': [['North', 'South', 'East', 'West'], ['Up', 'Down', 'Left', 'Right']]}
  • Each nesting level adds one dash and indentation.
  • Readability decreases with excessive nesting.

List with mixed nesting

Nested lists can represent matrices or multi-dimensional structures.

Code
data:
- - 1
- 2
- - 3
- 4
- - 5
- 6
Execution
python -c "import yaml; print(yaml.safe_load(open('mixed_nest.yaml')))"
Output
{'data': [[1, 2], [3, 4], [5, 6]]}
  • Consistent indentation is critical for correct parsing.

Complex Nesting

Combining lists and dictionaries in intricate structures.

List of objects with nested values

Complex structures combine list items (projects) with nested list values (tasks), each containing dictionaries.

Code
projects:
- name: ProjectA
status: active
tasks:
- name: Task 1
assigned_to: Alice
priority: high
- name: Task 2
assigned_to: Bob
priority: medium
- name: ProjectB
status: planning
tasks:
- name: Task 3
assigned_to: Carol
priority: high
Execution
python -c "import yaml; d = yaml.safe_load(open('projects.yaml')); print(d['projects'][0]['tasks'])"
Output
[{'name': 'Task 1', 'assigned_to': 'Alice', 'priority': 'high'}, {'name': 'Task 2', 'assigned_to': 'Bob', 'priority': 'medium'}]
  • The dash for list items aligns with the first key of each item.
  • Nested lists use additional indentation and dashes.

Hierarchical configuration

Hierarchical structures can represent multi-level configurations with lists of objects containing nested data.

Code
environments:
- name: development
services:
- name: api
port: 3000
env_vars:
DEBUG: 'true'
LOG_LEVEL: debug
- name: db
port: 5432
env_vars:
POSTGRES_DB: dev_db
- name: production
services:
- name: api
port: 8080
env_vars:
DEBUG: 'false'
LOG_LEVEL: error
Execution
python -c "import yaml; d = yaml.safe_load(open('envs.yaml')); print(len(d['environments'][0]['services']))"
Output
2
  • Maintain consistent indentation throughout complex nesting.
  • Document structure clearly to aid understanding.

Practical Examples

Real-world YAML usage, best practices, and solutions.

Configuration Files

Using YAML for application and service configuration.

Application configuration

Application configurations define settings for the entire application, including database and logging.

Code
app:
name: MyApplication
version: 1.0.0
port: 8000
database:
host: localhost
port: 5432
name: myapp_db
credentials:
username: app_user
password: secure_pwd
logging:
level: info
output: stdout
Execution
python -c "import yaml; conf = yaml.safe_load(open('app.yaml')); print(f\"App: {conf['app']['name']}, DB: {conf['database']['name']}\")"
Output
App: MyApplication, DB: myapp_db
  • Group related settings under common keys.
  • Use meaningful section names for clarity.

Docker Compose service

Docker Compose YAML defines multi-container services with images, ports, volumes, and environment variables.

Code
services:
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
environment:
NGINX_ENV: production
db:
image: postgres:13
environment:
POSTGRES_DB: mydb
POSTGRES_PASSWORD: secret
ports:
- "5432:5432"
Execution
Terminal window
docker-compose config
Output
Terminal window
services defined and validated
  • Each service is a list item with specific configuration.
  • Environment variables are key-value pairs in a dictionary.

Best Practices

Following YAML best practices for readability and maintainability.

Proper indentation and structure

Proper indentation, comments, and consistent structure improve readability and maintainability.

Code
# Database configuration - consistent spacing and indentation
database:
primary:
host: db-primary.example.com
port: 5432
credentials:
username: admin
password: secure_password
replica:
host: db-replica.example.com
port: 5432
credentials:
username: replica_user
password: replica_password
Execution
python -c "import yaml; print(yaml.safe_load(open('db_config.yaml')))"
Output
proper YAML structure loaded successfully
  • Use 2 spaces for each indentation level consistently.
  • Include comments explaining configuration purpose.

Avoiding common mistakes

Clear naming, proper structure, and meaningful comments make YAML files more maintainable.

Code
# Good: Clear naming and structure
services:
- name: api_service
port: 8000
timeout: 30
- name: worker_service
port: 8001
timeout: 60
# Bad: Unclear abbreviations and comments
# svc:
# - nm: api # Too abbreviated
# p: 8000
Execution
python -c "import yaml; d = yaml.safe_load(open('good.yaml')); print(f\"Services: {[s['name'] for s in d['services']]}\")"
Output
Services: ['api_service', 'worker_service']
  • Use full, descriptive names instead of abbreviations.
  • Avoid overly clever or minimal formatting.

Validation and Use

Parsing YAML, validating syntax, and loading in different languages.

Parsing YAML in Python

Python's `yaml` module (PyYAML) can parse YAML files into Python dictionaries.

Code
application:
name: PythonApp
debug: true
port: 5000
database:
host: localhost
port: 5432
Execution
import yaml
with open('app.yaml', 'r') as f:
config = yaml.safe_load(f)
print(config['application']['name'])
print(config['application']['database']['host'])
Output
PythonApp
localhost
  • Always use `safe_load()` to avoid executing arbitrary code.
  • Handle file exceptions for missing or invalid YAML files.

YAML validation

YAML validation tools check for syntax errors and formatting issues before using configuration.

Code
Terminal window
# Using yamllint for syntax validation
yamllint config.yaml
# Or validating with Python
python -c "import yaml; yaml.safe_load(open('config.yaml'))"
Execution
Terminal window
yamllint config.yaml
Output
Terminal window
config.yaml is valid
  • Use yamllint for comprehensive linting and style checking.
  • Python's `safe_load()` provides basic syntax validation.