Si alguna vez has gestionado un clúster de Kubernetes, configurado un flujo de trabajo de GitHub Actions, o escrito un archivo Docker Compose, ya has escrito YAML — probablemente mucho. YAML es el formato de configuración que impulsa la mayoría de las herramientas modernas de DevOps. Pero a pesar de estar en todas partes, es un formato que sorprende constantemente. He depurado más que mi cuota de errores de indentación YAML a las 11pm con un despliegue bloqueado. Asegurémonos de que tú no tengas que hacerlo.
YAML significa YAML Ain't Markup Language — sí, es un acrónimo recursivo. Originalmente era "Yet Another Markup Language" pero fue renombrado para enfatizar que es un formato de serialización de datos, no un lenguaje de marcado de documentos. La especificación YAML 1.2 es el estándar actual, aunque muchas herramientas todavía implementan YAML 1.1, que tiene algunas diferencias genuinamente peligrosas que cubriremos a continuación.
Los fundamentos: sintaxis YAML de un vistazo
YAML usa indentación (solo espacios — nunca tabulaciones) para expresar estructura. Un documento YAML es un mapping (pares clave-valor), una secuencia (una lista) o un escalar (un único valor). Aquí hay una configuración real estilo Kubernetes que cubre todos los elementos esenciales:
# This is a comment — YAML supports them, JSON does not
app:
name: payment-service
version: "2.1.0" # quoted to keep it a string
port: 8080
debug: false
timeout: 30.5
tags:
- payments
- backend
- critical
database:
host: postgres.internal
port: 5432
ssl: true
password: null # explicitly no valueSin llaves, sin comillas en la mayoría de las cadenas, sin comas. Para un archivo que los humanos editan cada día, esa claridad se acumula rápidamente. Pero YAML paga esa legibilidad con complejidad — hay mucho sucediendo bajo el capó.
Tipos escalares: cadenas, números, booleanos, null
YAML infiere tipos a partir de la apariencia del valor. Esto es conveniente la mayor parte del tiempo y silenciosamente catastrófico en algunos casos específicos.
# Strings — quotes are optional unless value is ambiguous
name: Alice
greeting: "Hello, world"
message: 'single quotes work too'
path: /usr/local/bin # unquoted — still a string
# Numbers
integer: 42
negative: -7
float: 3.14159
scientific: 6.022e23
# Booleans
ssl_enabled: true
verbose: false
# Null
api_key: null
legacy_field: ~ # tilde is also null in YAMLyes, no, on, off, true, false,
y, n, Y, N — y sus variantes en mayúsculas —
se interpretan como booleanos. Esto significa que el código de país ISO NO (Noruega) se convierte en el booleano
false. YAML 1.2 corrigió esto. Siempre pone entre comillas las cadenas que parecen booleanos. Consulta la
entrada de Wikipedia sobre el Problema Noruega
para toda la historia.# YAML 1.1 implicit type coercion — these silently become booleans:
country: NO # → false (Norway Problem!)
enabled: yes # → true
toggle: on # → true
# The fix: always quote when there's any ambiguity
country: "NO"
enabled: "yes"
version: "1.0" # also quote version numbers — 1.0 would be a floatSecuencias: listas en YAML
Las listas usan un prefijo guion-espacio. Cada elemento puede ser un escalar, un mapping u otra secuencia:
# Simple list
languages:
- Python
- Go
- TypeScript
# List of objects (common in Kubernetes)
containers:
- name: api
image: my-api:latest
port: 8080
- name: sidecar
image: envoy:v1.28
port: 9901
# Inline flow style (valid YAML, less readable)
tags: [payments, backend, v2]Cadenas multilínea: bloque literal vs bloque plegado
Aquí es donde YAML supera a JSON para archivos de configuración. Dos operadores especiales manejan cadenas multilínea de forma elegante:
# Literal block scalar (|) — preserves newlines exactly
startup_script: |
#!/bin/bash
set -e
echo "Starting service..."
npm start
# Folded scalar (>) — folds newlines into spaces (good for long descriptions)
description: >
This service handles payment processing
for all regions. It connects to Stripe
and falls back to PayPal.
# Result: "This service handles payment processing for all regions. It connects to Stripe and falls back to PayPal."
# Chomp modifiers
keep_trailing: |+
line one
line two
strip_trailing: |-
line one
line twoEl operador | es lo que hace legibles los scripts run: multilínea de GitHub Actions.
La hoja de referencia yaml-multiline.info
es la forma más rápida de recordar qué modificador de corte hace qué. Sin estos bloques escalares, estarías escribiendo
saltos de línea escapados en una sola cadena — lo que JSON te obliga a hacer.
Tabulaciones vs espacios — la regla cardinal
.yml y .yaml. Dos espacios es la
convención casi universal.Esta es la causa #1 de errores YAML crípticos. Una tabulación es idéntica a los espacios en la mayoría de los editores. Habilita "mostrar caracteres de espacio en blanco" en tu editor al depurar YAML, o pega tu archivo en el Validador YAML para obtener un mensaje de error claro apuntando a la línea exacta.
Ejemplo real: flujo de trabajo de GitHub Actions
Aquí hay un fragmento real de flujo de trabajo de GitHub Actions. Observa cómo el bloque run: multilínea
usa el bloque escalar literal, y cómo la indentación determina la estructura:
name: CI
on:
push:
branches: [main, develop]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
- name: Install dependencies
run: npm ci
- name: Run tests
run: |
npm run lint
npm run test -- --coverage
npm run buildEjemplo real: manifiesto de despliegue de Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-api
namespace: production
labels:
app: payment-api
version: "2.1.0"
spec:
replicas: 3
selector:
matchLabels:
app: payment-api
template:
metadata:
labels:
app: payment-api
spec:
containers:
- name: api
image: payment-api:2.1.0
ports:
- containerPort: 8080
env:
- name: NODE_ENV
value: production
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"Analizar YAML en Python y JavaScript
En Python, la biblioteca PyYAML
es la opción estándar. Siempre usa safe_load(), no load() — la versión insegura
puede ejecutar código Python arbitrario desde un archivo YAML:
import yaml
# Reading a YAML config file
with open('config.yaml', 'r') as f:
config = yaml.safe_load(f)
print(config['app']['name']) # payment-service
print(config['app']['port']) # 8080 (integer, not string)
print(config['app']['tags']) # ['payments', 'backend', 'critical']
# Writing Python data to YAML
data = {
'service': 'auth-api',
'replicas': 2,
'endpoints': ['/login', '/logout', '/refresh']
}
with open('output.yaml', 'w') as f:
yaml.dump(data, f, default_flow_style=False)En JavaScript/Node.js, js-yaml es la biblioteca más utilizada:
import yaml from 'js-yaml';
import fs from 'fs';
// Parse YAML string
const raw = fs.readFileSync('config.yaml', 'utf8');
const config = yaml.load(raw);
console.log(config.app.name); // payment-service
console.log(config.app.tags); // ['payments', 'backend', 'critical']
// Dump an object to YAML string
const output = yaml.dump({
name: 'my-service',
port: 3000,
tags: ['api', 'public']
});
console.log(output);Conclusión
La sintaxis basada en indentación de YAML, el soporte de comentarios y las cadenas multilínea legibles lo hacen la opción correcta para archivos de configuración que los humanos escriben y mantienen. Pero viene con trampas reales: el Problema Noruega, la confusión entre tabulaciones y espacios, y la coerción implícita de tipos de los parsers YAML 1.1. Conoce las reglas, pon entre comillas todo lo que sea ambiguo, configura tu editor para mostrar espacios en blanco, y usa un Formateador YAML para mantener archivos consistentes. YAML es una herramienta poderosa una vez que entiendes dónde muerde.