¿Qué es YAML?
YAML — YAML Ain't Markup Language (un acrónimo recursivo) — es un formato de serialización de datos legible por humanos diseñado para ser fácil de escribir a mano y fácil de leer sin herramientas especiales. Lanzado por primera vez en 2001, YAML es un superconjunto de JSON (todo documento JSON válido es YAML 1.2 válido), pero su principal atractivo es su sintaxis más limpia basada en la indentación para archivos de configuración y datos estructurados que los humanos necesitan leer y escribir frecuentemente.
YAML se ha convertido en el formato de configuración dominante para las herramientas de desarrollo: Docker Compose, manifiestos de Kubernetes, flujos de trabajo de GitHub Actions, playbooks de Ansible, Travis CI, GitLab CI, Helm charts y muchos archivos de configuración de aplicaciones usan YAML.
Fundamentos de Sintaxis YAML
Escalares (Cadenas, Números, Booleanos, Null)
nombre: Alicia
mensaje: "¡Hola, Mundo!"
multipalabra: esto es una cadena sin comillas
puerto: 8080
version: 3.14
activado: true
desactivado: false
base_de_datos: null
campo_opcional: ~
Secuencias (Listas)
# Estilo de bloque (recomendado para legibilidad)
frutas:
- manzana
- plátano
- cereza
# Estilo de flujo (compacto, como JSON)
colores: [rojo, verde, azul]
Mappings (Diccionarios)
servidor:
host: localhost
puerto: 5432
base_de_datos: mibbd
credenciales:
usuario: admin
contraseña: secreto
Cadenas Multilínea
# Literal de bloque (|) — preserva los saltos de línea
descripcion: |
Esta es la primera línea.
Esta es la segunda línea.
Se preserva el salto de línea final.
# Bloque plegado (>) — colapsa los saltos de línea en espacios
resumen: >
Este es un párrafo largo que se extiende
en varias líneas pero se colapsa
en una sola línea por los analizadores YAML.
Anclas (&) y Alias (*)
# Definir un bloque reutilizable con un ancla
predeterminados: &predeterminados
restart: always
logging:
driver: json-file
# Fusionar en otro mapping
web:
<<: *predeterminados
image: nginx:latest
ports:
- "80:80"
api:
<<: *predeterminados
image: myapp:latest
ports:
- "3000:3000"
La Diferencia entre YAML 1.1 y 1.2
El problema de Noruega proviene de que YAML 1.1 trata ciertas cadenas como booleanos:
# YAML 1.1 (PyYAML 5.x y anteriores):
# Estos se interpretan como booleano verdadero/falso:
activado: yes # True
desactivado: no # False ← "NO" → false, ¡el código ISO de Noruega "NO" se convierte en false!
bandera: on
interruptor: off
Siempre usa true/false para booleanos y comilla las cadenas que podrían malinterpretarse:
# Seguro — inequívoco en todas las versiones YAML
activado: true
pais: "NO"
estado: "on"
Trabajar con YAML en Python
PyYAML: La Biblioteca Estándar
pip install pyyaml
import yaml
# Leer YAML desde un archivo
with open('config.yaml', 'r', encoding='utf-8') as f:
config = yaml.safe_load(f)
print(config['servidor']['host'])
print(config['caracteristicas'])
# Escribir YAML
datos = {
'nombre': 'MiApp',
'version': '2.1.0',
'servidor': {'host': 'localhost', 'puerto': 8080},
'caracteristicas': ['auth', 'cache', 'logging'],
}
with open('salida.yaml', 'w', encoding='utf-8') as f:
yaml.dump(datos, f, default_flow_style=False,
allow_unicode=True, sort_keys=False)
Importante: Usa siempre yaml.safe_load() en lugar de yaml.load(). El load() inseguro puede ejecutar código Python arbitrario al analizar YAML no confiable.
ruamel.yaml: YAML con Preservación de Comentarios
PyYAML no preserva los comentarios al leer y volver a escribir YAML. ruamel.yaml sí lo hace:
pip install ruamel.yaml
from ruamel.yaml import YAML
def actualizar_yaml_preservando_comentarios(ruta: str, clave: str, valor) -> None:
"""Actualiza un valor en un archivo YAML preservando comentarios."""
yaml = YAML()
yaml.preserve_quotes = True
with open(ruta, 'r') as f:
datos = yaml.load(f)
claves = clave.split('.')
obj = datos
for k in claves[:-1]:
obj = obj[k]
obj[claves[-1]] = valor
with open(ruta, 'w') as f:
yaml.dump(datos, f)
actualizar_yaml_preservando_comentarios('config.yaml', 'servidor.puerto', 9090)
YAML en Configuraciones del Mundo Real
Docker Compose
version: "3.9"
services:
web:
image: nginx:alpine
ports:
- "80:80"
depends_on:
- app
app:
build: .
environment:
DATABASE_URL: postgresql://db:5432/miapp
DEBUG: "false"
restart: unless-stopped
db:
image: postgres:15
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: miapp
POSTGRES_USER: usuario
POSTGRES_PASSWORD: secreto
volumes:
postgres_data:
GitHub Actions
name: CI
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configurar Python
uses: actions/setup-python@v4
with:
python-version: "3.12"
- name: Instalar dependencias
run: pip install -r requirements.txt
- name: Ejecutar pruebas
run: pytest tests/ -v
Errores Comunes en YAML
Coerción implícita de tipos — YAML intenta inferir tipos de escalares sin comillas. version: 1.0 es un float; version: "1.0" es una cadena. Comilla los valores que deben permanecer como cadenas.
Indentación con tabulaciones — YAML prohíbe las tabulaciones para la indentación. Usa solo espacios.
Caracteres especiales en cadenas — Caracteres como :, {, }, [, ], ,, # pueden causar problemas de análisis cuando no están entre comillas.
Claves duplicadas — YAML técnicamente permite claves duplicadas en un mapping, pero el comportamiento es indefinido. Usa yamllint para detectarlas:
pip install yamllint
yamllint config.yaml
Conversiones relacionadas
Conversiones frecuentes del catálogo: