YAML vs JSON vs TOML: Cuándo Usar Cada Formato de Configuración
Todo proyecto eventualmente tiene un problema de configuración. Necesitas almacenar credenciales de base de datos, definir entornos de despliegue, describir un pipeline de CI o conectar dependencias — y alguien tiene que elegir un formato. ¿JSON? ¿YAML? ¿TOML? La elección parece arbitraria hasta que te muerde.
Los archivos de Docker Compose son YAML. package.json es JSON. El manifiesto de dependencias de Rust (Cargo.toml) es TOML. El empaquetado de Python (pyproject.toml) es TOML. Los flujos de trabajo de GitHub Actions son YAML. Esto no es aleatorio — cada formato ganó la batalla de adopción en su dominio por razones específicas. Entender esas razones te permite tomar una decisión deliberada en lugar de optar por "lo que usaba la plantilla."
Este artículo es una guía de decisión. Al final, conocerás los verdaderos compromisos de cada formato, verás los footguns exactos de YAML que han causado incidentes en producción, y tendrás un marco claro para elegir.
El Ancestro Común: Archivos INI
Antes de entrar en los contendientes modernos, vale la pena dedicar treinta segundos a los archivos INI — el formato al que los tres, en cierto sentido, están reaccionando.
Los archivos INI se ven así:
[database]
host = localhost
port = 5432
name = mydb
[server]
port = 8080
debug = trueSimple, legible por humanos, soporta secciones, soporta comentarios. Los problemas son igualmente simples: sin especificación estándar (cada parser interpreta los casos borde de forma diferente), sin estructuras anidadas más allá de un nivel, sin arrays, sin tipos explícitos. Todo es una cadena a menos que tu aplicación decida lo contrario.
INI estaba bien para php.ini en 1997. No está bien para describir un despliegue de Kubernetes en 2026. Pero identificó los objetivos correctos — editabilidad humana y comentarios — que los formatos modernos o bien heredaron o bien descartaron.
JSON: La Lingua Franca de los Datos
JSON (JavaScript Object Notation) fue estandarizado a principios de la década de 2000 y se convirtió en el formato wire dominante para las APIs. Su fortaleza proviene de sus restricciones.
Lo que JSON hace bien
JSON tiene exactamente seis tipos de valor: cadena, número, booleano, null, array y objeto. La especificación es inequívoca. Todo parser JSON compatible analizará el mismo documento de forma idéntica. No hay sorpresas.
{
"database": {
"host": "localhost",
"port": 5432,
"ssl": true
},
"allowed_origins": ["https://example.com", "https://api.example.com"],
"timeout_ms": null
}El tipo de port es inequívocamente un número. ssl es inequívocamente un booleano. allowed_origins es inequívocamente un array de cadenas. Un parser JSON no puede malinterpretar esto.
JSON también es ubicuo. Cada lenguaje tiene un parser JSON de biblioteca estándar. Los navegadores lo analizan de forma nativa. Bases de datos como PostgreSQL tienen columnas JSON nativas. Es el formato de mínimo común denominador para el intercambio de datos entre sistemas que no comparten un runtime.
Lo que JSON hace mal para la configuración
JSON no tiene sintaxis de comentarios. Esta es una decisión de diseño deliberada de Douglas Crockford (el creador de JSON), con el argumento de que los comentarios en formatos de datos alientan a las personas a poner directivas de análisis en ellos, lo que corrompe la portabilidad del formato.
Ese es un buen principio para las respuestas de API. Es un serio problema para los archivos de configuración. Los archivos de configuración necesitan comentarios. Necesitas explicar por qué timeout_ms es 30000 y no 10000. Necesitas marcar qué campos son seguros de cambiar. Necesitas dejar una nota que diga "no establezcas esto por encima de 100 en staging."
Las soluciones alternativas son todas malas. Algunos equipos usan campos "_comment". Algunos usan JSON5 (un superconjunto con comentarios) y esperan que sus herramientas lo manejen. Algunos usan JSONC (JSON con Comentarios, popularizado por el settings.json de VS Code). Ninguno de estos es JSON estándar.
JSON también es verboso para la configuración. Las comas finales no están permitidas, lo que provoca errores de sintaxis constantes al reordenar campos. Cada clave de cadena requiere comillas dobles. No hay sintaxis de cadena multilínea — un comando de shell largo tiene que escaparse en una sola línea.
JSON pertenece en: respuestas de API, intercambio de datos entre servicios, manifiestos de paquetes que son principalmente escritos por máquinas (package.json, composer.json), y en cualquier lugar donde necesites consistencia de análisis garantizada entre sistemas heterogéneos.
Puedes validar JSON en línea para detectar errores de sintaxis antes de que lleguen a tu aplicación — lo que importa más de lo que podrías esperar, ya que una sola coma faltante o corchete sobrante romperá completamente un parser JSON.
YAML: Poder y Peligro
YAML (YAML Ain't Markup Language) fue diseñado para ser la alternativa amigable para humanos a XML. Es expresivo, legible y ampliamente utilizado en las herramientas DevOps. También es el formato de configuración más peligroso en uso común.
Lo que YAML hace bien
YAML permite comentarios (#). Infiere tipos de valores sin comillas, por lo que puedes escribir port: 5432 en lugar de "port": 5432. Soporta cadenas multilínea con una sintaxis limpia similar a heredoc. Es conciso: la indentación reemplaza llaves y corchetes.
database:
host: localhost
port: 5432
ssl: true
allowed_origins:
- https://example.com
- https://api.example.com
# Este es un comentario que explica por qué el timeout es alto
timeout_ms: 30000Para las configuraciones de CI/CD — GitHub Actions, GitLab CI, CircleCI — la capacidad de YAML para expresar estructuras anidadas de forma limpia, con comentarios, es genuinamente útil. Un archivo de flujo de trabajo de GitHub Actions a menudo abarca cientos de líneas con condiciones anidadas, estrategias de matrix y bloques de variables de entorno. JSON sería ilegible. TOML sería incómodo para estructuras profundamente anidadas.
Los footguns de YAML
La inferencia de tipos de YAML es donde las cosas salen mal. El parser mira los valores sin comillas y decide de qué tipo son. Las decisiones que toma no siempre son las que esperas.
El Problema de Noruega. En YAML 1.1 (que es lo que implementa la mayoría de los parsers — no YAML 1.2), un NO simple se analiza como el booleano false. Lo mismo ocurre con no, No, n, N, false, False, FALSE, off, Off y OFF. Una lista de códigos de países ISO 3166-1 incluye NO para Noruega. Un archivo de configuración con una lista de códigos de países convertirá silenciosamente Noruega en false.
# YAML 1.1 — lo que el parser realmente ve
country: NO # → false (booleano)
enabled: yes # → true (booleano)
mode: on # → true (booleano)
debug: off # → false (booleano)La solución es entrecomillar todo lo que debería ser una cadena: country: "NO". Pero todo el atractivo de YAML es que no tienes que entrecomillar las cosas. Requerir comillas para evitar sorpresas erosiona la ventaja de legibilidad del formato.
Enteros octales. En YAML 1.1, un número que comienza con 0 se trata como octal. Los permisos de archivos se escriben comúnmente en octal: chmod: 0755. Un parser YAML lee 0755 como el número decimal 493, no 755. Esto ha roto scripts de despliegue reales.
# YAML 1.1 — interpretación octal
file_mode: 0755 # → 493 (equivalente decimal del octal 0755)Ambigüedad de cadenas multilínea. YAML ofrece múltiples sintaxis de cadenas multilínea — bloque literal (|), bloque plegado (>) y en línea. Se comportan de manera diferente con respecto a los saltos de línea, los espacios en blanco finales y la indentación. Elegir el incorrecto produce silenciosamente la cadena incorrecta.
# Bloque literal — preserva los saltos de línea
command: |
npm install
npm run build
# Bloque plegado — los saltos de línea se convierten en espacios (útil para texto largo)
description: >
Esta es una descripción larga que será
plegada en una sola línea con espacios.Tabulaciones vs espacios. YAML no permite caracteres de tabulación para la indentación. Un editor que inserta tabulaciones silenciosamente producirá un error de análisis — o peor, un análisis diferente dependiendo de la configuración del tabulador.
YAML 1.2 solucionó muchos de estos problemas (incluida la lista de valores booleanos), pero la mayoría de las herramientas aún implementan la versión 1.1. Cuando usas YAML, estás escribiendo para el parser que tu cadena de herramientas resulta tener, que puede o no coincidir con tus suposiciones.
TOML: Diseñado para Configuración
TOML (Tom's Obvious Minimal Language) fue creado en 2013 por Tom Preston-Werner (cofundador de GitHub) específicamente para ser un formato de archivo de configuración que los humanos puedan escribir y las máquinas puedan analizar sin ambigüedad.
Lo que TOML hace bien
TOML tiene tipos explícitos e inequívocos. Una cadena siempre está entre comillas. Un número siempre es un número. Un booleano siempre es true o false (minúsculas, sin alias). No hay inferencia de tipo de valores sin comillas, por lo que no hay Problema de Noruega.
[database]
host = "localhost"
port = 5432
ssl = true
allowed_origins = [
"https://example.com",
"https://api.example.com",
]
# Este es un comentario que explica por qué el timeout es alto
timeout_ms = 30000TOML tiene soporte de primera clase para fechas y horas (publishedAt = 2026-04-04), que JSON y YAML dejan como cadenas que las aplicaciones analizan por sí mismas.
Los encabezados de sección ([database], [[servers]]) son explícitos y legibles. Las claves con puntos (database.host = "localhost") te permiten expresar valores anidados en línea. El array de tablas ([[servers]]) te da una sintaxis limpia de lista de objetos.
[[servers]]
name = "production"
host = "prod.example.com"
port = 443
[[servers]]
name = "staging"
host = "staging.example.com"
port = 443La especificación TOML es precisa y versionada. Cada parser TOML conforme produce el mismo resultado para la misma entrada.
Dónde TOML se queda corto
TOML funciona bien para anidamiento de superficial a moderado. Para estructuras profundamente anidadas — del tipo que aparecen en los manifiestos de Kubernetes o los playbooks de Ansible — la sintaxis de encabezados de sección se vuelve repetitiva. El anidamiento basado en indentación de YAML escala más naturalmente a seis o siete niveles de profundidad.
TOML también tiene menos soporte de herramientas que JSON o YAML. La mayoría de los lenguajes tienen excelentes bibliotecas TOML, pero el soporte del editor (resaltado de sintaxis, validación, autocompletado) es menos consistente que el de JSON.
Tabla de Comparación
El Marco de Decisión
Una vez que eliminas el lenguaje de marketing, la elección se reduce a tres preguntas.
¿Es esto principalmente generado por máquina o escrito por humanos?
Si el archivo es generado por código y consumido por código — una respuesta de API, un artefacto de compilación, una entrada de caché serializada — usa JSON. Es el más portable, el más analizable y el soporte de herramientas es universal. No necesitas comentarios en un archivo que ningún humano lee. Comprimir estos archivos JSON antes de transferirlos a través de una red puede reducir significativamente el tamaño del payload.
Si un humano escribe y edita este archivo regularmente — una configuración de proyecto, una descripción de entorno, un manifiesto de herramienta — los comentarios son innegociables. Eso descarta el JSON simple.
¿Controlas la cadena de herramientas?
Si estás bloqueado en un ecosistema que exige un formato — Kubernetes requiere YAML, GitHub Actions requiere YAML, Cargo requiere TOML, package.json es JSON — no hay decisión que tomar. Usa lo que el ecosistema espera.
Si estás diseñando una nueva herramienta o un nuevo archivo de configuración desde cero, tienes una elección real.
¿Qué tan profundo es el anidamiento, y cuán tolerante es tu equipo con los bugs sutiles?
YAML es expresivo pero frágil. Un equipo que escribe YAML cuidadoso, entrecomilla todas las cadenas, ejecuta un linter y entiende la distinción entre las versiones 1.1 y 1.2 puede usarlo de forma segura. Un equipo que se mueve rápido, tiene configuraciones de editor diversas y no ejecuta linting de YAML en CI eventualmente encontrará un Problema de Noruega o un bug octal en producción.
TOML es la opción más segura para la configuración escrita por humanos cuando controlas el formato. Los tipos explícitos significan que el error del parser aparece en tiempo de análisis, no en tiempo de ejecución cuando Noruega se ha convertido en false y la lógica de tu feature flag falla silenciosamente.
Referencia rápida
- Respuesta de API o intercambio de datos entre servicios: JSON
- Manifiesto de paquete (principalmente escrito por máquinas): JSON
- Kubernetes, Docker Compose, GitHub Actions, Ansible: YAML (no es una elección)
- Nuevo archivo de configuración de proyecto que estás diseñando: TOML
- Proyecto Rust: TOML (
Cargo.toml) - Proyecto Python: TOML (
pyproject.toml) - Configuración de aplicación legacy con necesidades simples de clave-valor: INI (o migrar a TOML)
Validando tus Archivos de Configuración
Los errores de sintaxis en los archivos de configuración son algunos de los bugs más frustrantes de diagnosticar — la aplicación falla al arrancar, el mensaje de error es críptico y el error es un único carácter mal colocado.
Para JSON, puedes validar y formatear JSON en línea para detectar errores inmediatamente. Pegar un archivo de configuración JSON en un validador antes de confirmarlo toma cinco segundos y previene una clase de fallos de CI. Para flujos de trabajo JSON más profundos — minificar para producción, hacer diff de cambios de configuración entre entornos — consulta nuestra guía sobre cómo validar, minificar y formatear JSON.
Para YAML, yamllint es el linter CLI estándar. Ejecutarlo en CI no es opcional si tu equipo escribe YAML de producción. Para TOML, la mayoría de los ecosistemas de lenguaje incluyen un validador integrado (cargo check valida Cargo.toml implícitamente; python -c "import tomllib; tomllib.load(open('pyproject.toml', 'rb'))" valida cualquier archivo TOML directamente).
El Formato es un Contrato
Cualquiera que sea el formato que elijas, se convierte en un contrato con cada desarrollador y herramienta que toca tu proyecto. Cambiarlo más tarde es doloroso — no imposible, pero doloroso. La migración de setup.cfg y setup.py a pyproject.toml en el ecosistema Python tardó años y aún no está completa.
Elige deliberadamente. JSON cuando las máquinas son el consumidor principal y la portabilidad es crítica. YAML cuando el ecosistema lo exige o cuando las estructuras profundamente anidadas necesitan ser legibles. TOML cuando los humanos escriben el archivo, la corrección importa, y quieres que el parser detecte la ambigüedad en tiempo de lectura en lugar de que aparezca como un bug en tiempo de ejecución seis meses después.
El formato de configuración no es solo un formato de archivo. Es una declaración sobre quién edita el archivo, qué herramientas lo procesan y cuánto confías en la coerción de tipos implícita. Haz esa declaración a propósito.
¿Necesitas validar un archivo de configuración JSON ahora mismo? Prueba el FileCrank JSON Viewer — pega tu JSON, detecta errores al instante y dale formato para mayor legibilidad.