Ouvrez n'importe quel projet Rust et vous trouverez un Cargo.toml. Clonez un dépôt
GitHub et vous découvrirez un dossier .github/workflows/ rempli de YAML. Les deux formats
accomplissent le même travail de surface — stocker une configuration structurée que les humains
modifient — mais ils font des compromis très différents. Si vous avez déjà eu du YAML qui altère
silencieusement une valeur, ou si vous vous êtes demandé pourquoi Rust a choisi TOML plutôt que
YAML pour son manifeste de paquet, cet article est fait pour vous.
La différence fondamentale : explicite vs implicite
La différence essentielle entre TOML et YAML concerne la latitude laissée au parseur pour
deviner. TOML est explicite : chaque
valeur a un type non ambigu. Les chaînes sont toujours entre guillemets. Les booléens sont exactement
true ou false. Les datetimes sont des valeurs de première classe avec leur
propre syntaxe. Il n'y a pas de coercition de type implicite — le parseur ne cherche pas à être
intelligent.
YAML penche de l'autre côté.
Il essaie d'être pratique : vous n'avez pas besoin de guillemets autour de la plupart des chaînes, et
le parseur déduit les types à partir de l'apparence des valeurs. C'est cette inférence qui piège les
gens. La spécification YAML 1.1 (encore utilisée par de nombreux outils) traite yes,
no, on, off, true et false comme des
booléens. Elle interprète les chaînes de version non quotées comme 1.0 comme des flottants.
Et puis il y a le problème de la Norvège.
Les pièges célèbres de YAML
Le problème de la Norvège est devenu un mème dans les cercles DevOps. En YAML 1.1, le code
pays NO est parsé comme le booléen false. Ainsi, une configuration mappant
des codes de pays ISO à des paramètres convertirait silencieusement l'entrée de la Norvège en booléen.
La spécification YAML 1.2
a corrigé cela, mais de nombreux parseurs largement utilisés — dont le mode par défaut de PyYAML
jusqu'à récemment — ciblent encore YAML 1.1. Vérifiez quelle version de spécification votre outillage
implémente réellement avant de lui faire confiance.
NO,
Yes, on et off non quotés deviennent tous des booléens. La
solution est simple — mettre les chaînes entre guillemets — mais le problème est que c'est silencieux.
Votre configuration se charge sans erreur et vous obtenez un booléen là où vous attendiez une chaîne.# YAML 1.1 implicit type coercion — all of these silently become booleans:
countries:
norway: NO # → false ← The Norway Problem
sweden: SE # → "SE" (fine, not in the boolean list)
enabled: yes # → true
disabled: no # → false
feature_flag: on # → true
another: off # → false
# Version strings can become numbers:
python_version: 3.10 # → float 3.1 (trailing zero dropped)
api_version: 1.0 # → float 1.0
# Safe: quote anything that could be ambiguous
python_version: "3.10"
country: "NO"
enabled: "yes"- Littéraux octaux. En YAML 1.1,
010est parsé comme8(octal), pas10. Cela importe pour les valeurs de permissions de fichiers comme0755. - Tabulation vs espace. YAML interdit les caractères de tabulation pour l'indentation. Collez du code depuis un éditeur configuré pour utiliser des tabulations et vous obtenez une erreur de parsage cryptique — ou pire, un décalage silencieux.
- Nulls implicites. Une clé sans valeur devient
null. Facile à créer accidentellement lors d'une édition manuelle. - Sensibilité à l'indentation. Un espace supplémentaire et une valeur se déplace silencieusement d'un parent à un autre. Pas d'erreur, juste des données incorrectes.
TOML : à quoi ressemblent vraiment les types explicites
Le système de types de TOML est détaillé dans la
spécification TOML v1.0. Les
chaînes doivent être entre guillemets (simples ou doubles). Les booléens sont true ou
false et rien d'autre. Les entiers sont des entiers. Les flottants sont des flottants.
Et les datetimes — quelque chose que ni JSON ni YAML n'a comme type natif — sont des valeurs de
première classe en TOML.
# TOML types are always unambiguous
name = "my-app" # string — must be quoted
version = "1.0.0" # string — quotes make it clear this is not a float
port = 8080 # integer
debug = false # boolean — only true/false, nothing else
threshold = 0.95 # float
# Datetime is a first-class type — no string parsing needed
created_at = 2024-01-15T09:30:00Z
build_date = 2024-03-20
# Arrays
allowed_hosts = ["localhost", "staging.example.com", "api.example.com"]
# Inline tables
[database]
host = "postgres.internal"
port = 5432
name = "payments_prod"
pool_size = 20Le code pays NO est simplement une chaîne en TOML parce qu'il n'est pas entre
guillemets, mais TOML n'infère pas les types à partir de valeurs ressemblant à des chaînes — les
valeurs non quotées suivent des règles syntaxiques strictes. Pour être une chaîne, des guillemets sont
nécessaires. TOML n'a tout simplement pas le mécanisme de coercition implicite qui cause les pièges
de YAML.
Côte à côte : une configuration de pipeline CI
Voici un workflow GitHub Actions — c'est le terrain de prédilection de YAML. Le format s'adapte naturellement car GitHub Actions attend du YAML, l'imbrication basée sur l'indentation reflète la structure logique, et les commentaires sont essentiels pour expliquer les configurations d'étapes non évidentes.
# .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
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 test
- name: Build
run: npm run build --if-present
- name: Publish to npm
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}Voici maintenant le manifeste de projet équivalent en TOML — c'est là que TOML brille. Comparez une vraie structure Cargo.toml avec ce à quoi la même configuration ressemblerait en YAML :
# Cargo.toml — Rust package manifest
[package]
name = "payments-service"
version = "2.4.1"
edition = "2021"
description = "Payment processing microservice"
license = "MIT"
authors = ["Alice Chen <[email protected]>"]
[dependencies]
tokio = { version = "1.35", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio-native-tls"] }
tracing = "0.1"
anyhow = "1.0"
[dev-dependencies]
tokio-test = "0.4"
wiremock = "0.6"
[profile.release]
opt-level = 3
lto = true
codegen-units = 1Les faiblesses de TOML : tableau de tables
TOML n'est pas sans aspérités. La syntaxe pour les tableaux de tables —
[[double brackets]] — est l'une des choses les plus déroutantes dans la spécification.
C'est ainsi que vous exprimez ce que JSON écrirait comme un tableau d'objets, et cela semble étrange
au premier abord.
# TOML array of tables — [[double brackets]] creates array entries
[[server]]
host = "web-01.example.com"
port = 443
region = "us-east-1"
[[server]]
host = "web-02.example.com"
port = 443
region = "us-west-2"
[[server]]
host = "web-03.example.com"
port = 443
region = "eu-west-1"
# The above is equivalent to this JSON:
# { "server": [
# { "host": "web-01.example.com", "port": 443, "region": "us-east-1" },
# { "host": "web-02.example.com", "port": 443, "region": "us-west-2" },
# { "host": "web-03.example.com", "port": 443, "region": "eu-west-1" }
# ]}En YAML, la même structure se lit plus naturellement — juste une liste avec des propriétés
indentées. Pour des données profondément imbriquées avec des entrées de tableau répétées, l'imbrication
basée sur l'indentation de YAML est véritablement moins verbeuse que les en-têtes
[[section]] de TOML. TOML n'a également pas d'équivalent au système d'ancres et d'alias
de YAML, vous ne pouvez donc pas définir un bloc partagé une fois et le référencer ailleurs. Si vous
vous retrouvez à dupliquer le même ensemble de valeurs dans plusieurs tables TOML, vous êtes obligé de
les copier manuellement.
Où chaque format gagne en pratique
YAML gagne par défaut dans ces écosystèmes :
- GitHub Actions. La totalité de la syntaxe de workflow est en YAML. Vous n'avez pas le choix ici, et c'est bien — l'indentation correspond bien à la structure imbriquée des jobs, étapes et conditions.
- Kubernetes. Chaque manifeste — Deployments, Services, ConfigMaps, règles Ingress — est en YAML. Le modèle objet Kubernetes est profondément imbriqué, et YAML gère cela avec élégance.
- Docker Compose. Définitions de services, réseaux, volumes — tout en YAML. Les commentaires expliquant pourquoi un port est exposé ou pourquoi un intervalle de healthcheck spécifique est utilisé font partie de la documentation.
- Ansible. Playbooks, rôles, fichiers de variables — YAML partout. Le support des commentaires est activement utilisé pour expliquer les paramètres de tâches non évidents.
TOML gagne quand vous contrôlez le format :
- Projets Rust.
Cargo.tomlest la référence absolue. Déclarations de dépendances, feature flags, profils de build — tout en TOML. Les types explicites signifient que les chaînes de version comme"1.0.0"restent des chaînes. - Projets Python.
pyproject.tomlest devenu le standard pour les métadonnées de projets Python, la configuration de build, et les paramètres d'outils (Black, isort, mypy, pytest lisent tous depuis ce fichier). - Configuration d'outils où l'ambiguïté cause des bugs. Si votre configuration contient des chaînes de version, des codes de pays, ou d'autres valeurs qui pourraient ressembler à des booléens ou des nombres, les types explicites de TOML éliminent toute une catégorie de surprises de parsage.
- Configurations plates. Quand votre configuration est principalement des paires clé-valeur à un ou deux niveaux d'imbrication, TOML est plus lisible que YAML et plus propre que JSON.
Le guide de décision pratique
La plupart du temps, le choix est fait pour vous par l'écosystème. GitHub Actions, c'est YAML. Kubernetes, c'est YAML. Rust, c'est TOML. L'outillage Python, c'est TOML. Quand vous avez vraiment le choix, utilisez ce guide :
- Utilisez YAML quand l'outillage l'impose — plateformes CI/CD, Kubernetes, charts Helm, Docker Compose, Ansible. Combattre la convention coûte plus que ça ne rapporte.
- Utilisez YAML quand vous avez besoin d'ancres et d'alias pour garder une configuration complexe DRY — il n'y a pas d'équivalent TOML.
- Utilisez TOML pour les manifestes de projets et la configuration d'outils que vous contrôlez — métadonnées de paquets, paramètres de linters, configuration de build.
- Utilisez TOML quand votre configuration contient des valeurs que YAML 1.1 pourrait mal interpréter — chaînes de version, codes de pays, tout ce qui ressemble à un booléen ou un nombre.
- Mettez vos chaînes YAML entre guillemets chaque fois que la valeur pourrait être
confondue avec un booléen, un nombre ou null. Particulièrement : les numéros de version, les codes
de pays, tout ce qui commence par un chiffre, et les valeurs comme
yes,no,on,off.
Travailler avec les deux formats
Besoin de valider ou de mettre en forme un fichier de configuration ? Le Formateur TOML gère les fichiers TOML, et le Formateur YAML couvre YAML. Si vous devez migrer une configuration d'un format à l'autre — par exemple, convertir une configuration d'outil basée sur YAML en TOML pour un projet qui le préfère — les convertisseurs TOML vers JSON et YAML vers JSON produisent tous deux du JSON, que vous pouvez ensuite convertir vers votre format cible. Parfois, passer par JSON comme étape intermédiaire est le chemin le plus fiable.
Une chose à savoir : les deux formats ont leurs propres sous-ensembles compatibles JSON. Le JSON valide est du YAML valide (YAML est un sur-ensemble de JSON). TOML n'a pas cette relation avec JSON, mais la spécification TOML est intentionnellement simple — c'est une lecture courte, ce qu'on ne peut pas dire de la spécification YAML 1.2 complète.
En conclusion
TOML et YAML ne sont pas vraiment en compétition. Ils se sont installés dans des niches différentes basées sur leurs priorités de conception. Les types implicites et la structure basée sur l'indentation de YAML en font le choix naturel pour les grandes configurations imbriquées maintenues par des équipes — pensez aux manifestes Kubernetes et aux workflows GitHub Actions. Les types explicites et la structure de sections plates de TOML en font le choix naturel pour les manifestes de projets et la configuration d'outils où une chaîne de version ou un code pays mal lu causerait un vrai bug.
La seule chose à retenir : si vous écrivez du YAML et que vous avez des valeurs qui
ressemblent à des booléens, des nombres ou des nulls — mettez-les entre guillemets. C'est la
seule habitude qui prévient la plupart des bugs de configuration liés à YAML. Et si vous démarrez
un nouveau projet et avez le choix de votre format de configuration, TOML vaut le coup d'œil. Le
dépôt GitHub TOML
contient de bons exemples, et une fois que vous avez écrit un Cargo.toml ou un
pyproject.toml, l'attrait du format devient assez évident.