Convertisseur JSON ↔ YAML en ligne

🏷️ Outils Web Essentiels 100% Gratuit 🧰 Utilitaires Web 👤 AngularForAll
Json To Yaml Yaml To Json Convertisseur Json Convertisseur Yaml Outil Développeur Devtools

Convertissez instantanément JSON en YAML et YAML en JSON dans votre navigateur. Conversion automatique, formatage, tri des clés, téléchargement du fichier. 100% local, aucune donnée envoyée.

🔀

Convertisseur JSON ↔ YAML

JSON → YAML

JSON vs YAML : différences clés

JSON (JavaScript Object Notation) et YAML (YAML Ain't Markup Language) sont deux formats de sérialisation de données. YAML est un sur-ensemble de JSON : tout JSON valide est aussi du YAML valide.

CritèreJSONYAML
Lisibilité humaineMoyenne✅ Excellente
Commentaires❌ Non✅ Oui (# commentaire)
VerbositéAccolades, guillemetsIndentation uniquement
Usage principalAPIs REST, configs JSDocker, Kubernetes, CI/CD
ParsingTrès rapidePlus complexe
MultilignesAvec \n✅ Natif (| et >)

Syntaxe YAML expliquée

Voici les équivalences JSON ↔ YAML pour les structures les plus courantes :

# YAML — Objet simple
name: Alice
age: 30
active: true
score: 9.5
address: null

# JSON équivalent
{
  "name": "Alice",
  "age": 30,
  "active": true,
  "score": 9.5,
  "address": null
}

Objets imbriqués et listes :

# YAML
user:
  name: Alice
  roles:
    - admin
    - editor
  address:
    city: Paris
    zip: "75001"

# JSON équivalent
{
  "user": {
    "name": "Alice",
    "roles": ["admin", "editor"],
    "address": { "city": "Paris", "zip": "75001" }
  }
}

Types de données

TypeYAMLJSON
Chaînename: Alice ou name: "Alice""name": "Alice"
Entierage: 30"age": 30
Flottantscore: 9.5"score": 9.5
Booléenactive: true"active": true
Nulldata: null ou data: ~"data": null
Liste- item1
- item2
["item1", "item2"]
ObjetClés indentées{ "key": "val" }

Cas d'usage courants

  • Docker Composedocker-compose.yml
  • Kubernetes — manifests (deployment.yaml, service.yaml)
  • GitHub Actions / GitLab CI — pipelines CI/CD
  • Ansible — playbooks et inventaires
  • OpenAPI / Swagger — spec d'API en YAML
  • Configurations d'apps — Spring Boot (application.yml), Rails (database.yml)
Conseil : utilisez JSON pour les APIs REST (meilleure interop navigateur) et YAML pour les fichiers de configuration (lisibilité + commentaires).

Astuces et pièges

  • ⚠️ Les tabulations sont interdites en YAML — toujours utiliser des espaces
  • ⚠️ yes, no, on, off sont des booléens en YAML 1.1 — entourer de guillemets si c'est une chaîne
  • ⚠️ Les zéros initiaux (075) sont interprétés comme octaux — utiliser des guillemets
  • Strings multilignes : | conserve les sauts de ligne, > les remplace par des espaces
  • Ancres et alias : &anchor définit, *alias réutilise — évite la duplication
# Multilignes YAML
description: |
  Ligne 1
  Ligne 2
  Ligne 3

# Ancres (DRY)
defaults: &defaults
  timeout: 30
  retries: 3

production:
  <<: *defaults
  url: https://prod.example.com
if (jyDir === 'json2yaml') { jySet('jy-input-label', '📥 JSON (input)'); jySet('jy-output-label', '📤 YAML (output)'); jySet('jy-dir-badge', 'JSON → YAML'); jyEl('jy-input').placeholder = 'Collez votre JSON ici...'; jyEl('jy-output').placeholder = 'Le YAML généré apparaîtra ici...'; } else { jySet('jy-input-label', '📥 YAML (input)'); jySet('jy-output-label', '📤 JSON (output)'); jySet('jy-dir-badge', 'YAML → JSON'); jyEl('jy-input').placeholder = 'Collez votre YAML ici...'; jyEl('jy-output').placeholder = 'Le JSON généré apparaîtra ici...'; } } function jyStats(text, elId) { if (!text.trim()) { jySet(elId, ''); return; } var lines = text.split('\n').length; var bytes = new Blob([text]).size; jySet(elId, lines + ' lignes · ' + (bytes > 1024 ? (bytes/1024).toFixed(1) + ' Ko' : bytes + ' o')); } // ── JSON → YAML ─────────────────────────────────────────────────────────── function jsonToYaml(obj, indent, level) { var pad = ' '.repeat(indent * level); var pad1 = ' '.repeat(indent * (level + 1)); var type = Array.isArray(obj) ? 'array' : (obj === null ? 'null' : typeof obj); if (type === 'null') return 'null'; if (type === 'boolean') return String(obj); if (type === 'number') return String(obj); if (type === 'string') return jyQuoteString(obj); if (type === 'array') { if (obj.length === 0) return '[]'; return obj.map(function(item) { var itemType = Array.isArray(item) ? 'array' : (item === null ? 'null' : typeof item); if (itemType === 'object' || itemType === 'array') { var inner = jsonToYaml(item, indent, level + 1); // L'objet/array inline commence juste après le tiret var firstNL = inner.indexOf('\n'); if (firstNL === -1) return pad + '- ' + inner; // multi-lignes: première ligne après le tiret, reste indenté var firstLine = inner.slice(0, firstNL); var rest = inner.slice(firstNL + 1).split('\n').map(function(l) { return pad + ' ' + l; }).join('\n'); return pad + '- ' + firstLine + '\n' + rest; } return pad + '- ' + jsonToYaml(item, indent, level); }).join('\n'); } if (type === 'object') { var keys = Object.keys(obj); if (jyEl('jy-sort-keys').checked) keys = keys.sort(); if (keys.length === 0) return '{}'; return keys.map(function(k) { var val = obj[k]; var valType = Array.isArray(val) ? 'array' : (val === null ? 'null' : typeof val); var safeKey = jyQuoteKey(k); if (valType === 'object' && val !== null && Object.keys(val).length > 0) { return pad + safeKey + ':\n' + jsonToYaml(val, indent, level + 1); } if (valType === 'array' && val.length > 0) { return pad + safeKey + ':\n' + jsonToYaml(val, indent, level + 1); } return pad + safeKey + ': ' + jsonToYaml(val, indent, level); }).join('\n'); } return String(obj); } // Cas où une string YAML doit être entre guillemets var JY_NEEDS_QUOTE = /^[\s]|[\s]$|^[-?:,[\]{}#&*!|>'"%@`]|^(true|false|null|~|yes|no|on|off)$/i; var JY_SPECIAL_CHARS = /[:\n#\[\]{}]/; function jyQuoteString(s) { if (s === '') return '""'; if (JY_NEEDS_QUOTE.test(s) || JY_SPECIAL_CHARS.test(s)) { return '"' + s.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r') + '"'; } return s; } function jyQuoteKey(k) { if (/^[a-zA-Z_][a-zA-Z0-9_\-]*$/.test(k) && !JY_NEEDS_QUOTE.test(k)) return k; return '"' + k.replace(/"/g, '\\"') + '"'; } // ── YAML → JSON ─────────────────────────────────────────────────────────── function yamlToJson(yaml) { var lines = yaml.split('\n'); // Supprimer les commentaires de fin de ligne et lignes vides var cleaned = []; for (var i = 0; i < lines.length; i++) { var line = lines[i]; // Supprimer commentaires (hors strings) var stripped = jyStripComment(line); cleaned.push(stripped); } var result = jyParseYamlLines(cleaned, 0, cleaned.length, 0); return result.value; } function jyStripComment(line) { // Retire le commentaire inline hors string var inStr = false; var strChar = ''; for (var i = 0; i < line.length; i++) { var c = line[i]; if (inStr) { if (c === '\\') { i++; continue; } if (c === strChar) inStr = false; } else { if (c === '"' || c === "'") { inStr = true; strChar = c; } else if (c === '#') { return line.slice(0, i).trimRight(); } } } return line; } function jyGetIndent(line) { var m = line.match(/^(\s*)/); return m ? m[1].length : 0; } function jyParseYamlLines(lines, start, end, baseIndent) { // Trouver le type : mapping ou sequence ? var firstReal = -1; for (var i = start; i < end; i++) { if (lines[i].trim() !== '') { firstReal = i; break; } } if (firstReal === -1) return { value: null, next: end }; var firstTrimmed = lines[firstReal].trim(); // Séquence : commence par "- " if (firstTrimmed.startsWith('- ') || firstTrimmed === '-') { return jyParseSequence(lines, start, end, baseIndent); } // Mapping : contient ": " if (firstTrimmed.includes(': ') || firstTrimmed.endsWith(':')) { return jyParseMapping(lines, start, end, baseIndent); } // Scalaire seul return { value: jyParseScalar(firstTrimmed), next: firstReal + 1 }; } function jyParseMapping(lines, start, end, baseIndent) { var obj = {}; var i = start; while (i < end) { var line = lines[i]; if (line.trim() === '') { i++; continue; } var indent = jyGetIndent(line); if (indent < baseIndent) break; if (indent > baseIndent) { i++; continue; } var trimmed = line.trim(); // Clé: valeur var colonIdx = trimmed.indexOf(': '); var key, rawVal; if (colonIdx !== -1) { key = jyUnquote(trimmed.slice(0, colonIdx).trim()); rawVal = trimmed.slice(colonIdx + 2).trim(); } else if (trimmed.endsWith(':')) { key = jyUnquote(trimmed.slice(0, -1).trim()); rawVal = ''; } else { i++; continue; } if (rawVal === '' || rawVal === '|' || rawVal === '>') { // Valeur sur les lignes suivantes var childIndent = -1; var j = i + 1; while (j < end && lines[j].trim() === '') j++; if (j < end) childIndent = jyGetIndent(lines[j]); if (rawVal === '|' || rawVal === '>') { // Multiline scalar var mlLines = []; var mli = i + 1; while (mli < end && (lines[mli].trim() === '' || jyGetIndent(lines[mli]) > indent)) { mlLines.push(lines[mli].slice(childIndent)); mli++; } // Retirer trailing newlines while (mlLines.length > 0 && mlLines[mlLines.length-1].trim() === '') mlLines.pop(); obj[key] = rawVal === '|' ? mlLines.join('\n') : mlLines.join(' ').replace(/\s+/g, ' ').trim(); i = mli; } else if (childIndent > indent) { var parsed = jyParseYamlLines(lines, j, end, childIndent); obj[key] = parsed.value; i = parsed.next; } else { obj[key] = null; i++; } } else if (rawVal === '[]') { obj[key] = []; i++; } else if (rawVal === '{}') { obj[key] = {}; i++; } else if (rawVal.startsWith('[') && rawVal.endsWith(']')) { // Inline array obj[key] = jyParseInlineArray(rawVal); i++; } else if (rawVal.startsWith('{') && rawVal.endsWith('}')) { // Inline object obj[key] = jyParseInlineObject(rawVal); i++; } else { obj[key] = jyParseScalar(rawVal); i++; } } return { value: obj, next: i }; } function jyParseSequence(lines, start, end, baseIndent) { var arr = []; var i = start; while (i < end) { var line = lines[i]; if (line.trim() === '') { i++; continue; } var indent = jyGetIndent(line); if (indent < baseIndent) break; if (indent > baseIndent) { i++; continue; } var trimmed = line.trim(); if (!trimmed.startsWith('-')) { i++; continue; } var rest = trimmed.slice(1).trim(); if (rest === '') { // Valeur sur les lignes suivantes var j = i + 1; while (j < end && lines[j].trim() === '') j++; if (j < end && jyGetIndent(lines[j]) > indent) { var parsed = jyParseYamlLines(lines, j, end, jyGetIndent(lines[j])); arr.push(parsed.value); i = parsed.next; } else { arr.push(null); i++; } } else if (rest.includes(': ') || rest.endsWith(':')) { // Inline mapping démarrant après le tiret var fakeLine = ' '.repeat(indent + 2) + rest; var subLines = [fakeLine]; var si = i + 1; while (si < end) { var sLine = lines[si]; if (sLine.trim() === '') { subLines.push(''); si++; continue; } if (jyGetIndent(sLine) <= indent) break; subLines.push(sLine); si++; } var subParsed = jyParseMapping(subLines, 0, subLines.length, indent + 2); arr.push(subParsed.value); i = si; } else if (rest.startsWith('[') && rest.endsWith(']')) { arr.push(jyParseInlineArray(rest)); i++; } else { arr.push(jyParseScalar(rest)); i++; } } return { value: arr, next: i }; } function jyParseInlineArray(s) { // Parsing simple de tableau inline YAML/JSON ex: [1, "a", true] try { return JSON.parse(s); } catch(e) {} var inner = s.slice(1, -1).trim(); if (!inner) return []; return inner.split(',').map(function(x) { return jyParseScalar(x.trim()); }); } function jyParseInlineObject(s) { try { return JSON.parse(s); } catch(e) {} var obj = {}; var inner = s.slice(1, -1).trim(); if (!inner) return obj; inner.split(',').forEach(function(pair) { var ci = pair.indexOf(':'); if (ci === -1) return; var k = jyUnquote(pair.slice(0, ci).trim()); var v = jyParseScalar(pair.slice(ci + 1).trim()); obj[k] = v; }); return obj; } var JY_BOOL_TRUE = /^(true|yes|on)$/i; var JY_BOOL_FALSE = /^(false|no|off)$/i; function jyParseScalar(s) { if (s === '' || s === '~' || s === 'null') return null; if (JY_BOOL_TRUE.test(s)) return true; if (JY_BOOL_FALSE.test(s)) return false; if (s.startsWith('"') || s.startsWith("'")) return jyUnquote(s); if (!isNaN(Number(s)) && s !== '') return Number(s); return s; } function jyUnquote(s) { if (!s) return s; if (s.startsWith('"') && s.endsWith('"')) { return s.slice(1, -1).replace(/\\"/g, '"').replace(/\\n/g, '\n').replace(/\\r/g, '\r').replace(/\\\\/g, '\\'); } if (s.startsWith("'") && s.endsWith("'")) { return s.slice(1, -1).replace(/''/g, "'"); } return s; } // ── Conversion principale ───────────────────────────────────────────────── function jyConvert() { var input = jyV('jy-input'); var indent = parseInt(jyV('jy-indent')) || 2; var jsonIndent= parseInt(jyV('jy-json-indent')) || 2; var errEl = jyEl('jy-input-error'); var outEl = jyEl('jy-output'); var outErrEl = jyEl('jy-output-error'); errEl.textContent = ''; outErrEl.textContent = ''; outEl.classList.remove('error', 'success'); jyEl('jy-input').classList.remove('error', 'success'); if (!input.trim()) { outEl.value = ''; jyStats('', 'jy-output-info'); return; } try { var result; if (jyDir === 'json2yaml') { var parsed = JSON.parse(input); if (jyEl('jy-sort-keys').checked && typeof parsed === 'object' && !Array.isArray(parsed)) { parsed = jySortObj(parsed); } result = jsonToYaml(parsed, indent, 0); } else { var obj = yamlToJson(input); result = JSON.stringify(obj, jyEl('jy-sort-keys').checked ? Object.keys(obj||{}).sort() : null, jsonIndent); } outEl.value = result; outEl.classList.add('success'); jyEl('jy-input').classList.add('success'); jyStats(result, 'jy-output-info'); } catch (e) { outEl.value = ''; jyEl('jy-input').classList.add('error'); errEl.textContent = '⚠️ ' + e.message; jyStats('', 'jy-output-info'); } } function jySortObj(obj) { if (Array.isArray(obj)) return obj.map(jySortObj); if (obj && typeof obj === 'object') { var sorted = {}; Object.keys(obj).sort().forEach(function(k) { sorted[k] = jySortObj(obj[k]); }); return sorted; } return obj; } function jyOnInput() { jyStats(jyV('jy-input'), 'jy-input-info'); if (jyEl('jy-auto').checked) jyConvert(); } // ── Swap ────────────────────────────────────────────────────────────────── function jySwap() { var prevOutput = jyV('jy-output'); jyEl('jy-input').value = prevOutput; jyEl('jy-output').value = ''; jyEl('jy-input-error').textContent = ''; jyEl('jy-output-error').textContent = ''; jyEl('jy-output').classList.remove('error', 'success'); jyEl('jy-input').classList.remove('error', 'success'); jyDir = jyDir === 'json2yaml' ? 'yaml2json' : 'json2yaml'; jyUpdateLabels(); jyStats(prevOutput, 'jy-input-info'); if (jyEl('jy-auto').checked) jyConvert(); } // ── Format input ───────────────────────────────────────────────────────── function jyFormatInput() { var val = jyV('jy-input'); if (!val.trim()) return; try { if (jyDir === 'json2yaml') { var jsonIndent = parseInt(jyV('jy-json-indent')) || 2; jyEl('jy-input').value = JSON.stringify(JSON.parse(val), null, jsonIndent); } jyOnInput(); } catch(e) { /* ignore */ } } // ── Exemples ───────────────────────────────────────────────────────────── var JY_SAMPLE_JSON = JSON.stringify({ "name": "mon-app", "version": "1.0.0", "author": { "name": "Alice", "email": "alice@example.com" }, "dependencies": { "express": "^4.18.0", "mongoose": "^8.0.0" }, "scripts": { "start": "node server.js", "test": "jest" }, "ports": [3000, 8080], "active": true, "description": null }, null, 2); var JY_SAMPLE_YAML = [ 'name: mon-app', 'version: 1.0.0', '', 'author:', ' name: Alice', ' email: alice@example.com', '', 'dependencies:', ' express: "^4.18.0"', ' mongoose: "^8.0.0"', '', 'scripts:', ' start: node server.js', ' test: jest', '', 'ports:', ' - 3000', ' - 8080', '', 'active: true', 'description: null' ].join('\n'); function jyLoadSample() { jyEl('jy-input').value = jyDir === 'json2yaml' ? JY_SAMPLE_JSON : JY_SAMPLE_YAML; jyOnInput(); } // ── Actions ─────────────────────────────────────────────────────────────── function jyClearInput() { jyEl('jy-input').value = ''; jyEl('jy-output').value = ''; jyEl('jy-input-error').textContent = ''; jyEl('jy-output-error').textContent = ''; jyEl('jy-input').classList.remove('error', 'success'); jyEl('jy-output').classList.remove('error', 'success'); jyStats('', 'jy-input-info'); jyStats('', 'jy-output-info'); } function jyCopyOutput() { var text = jyV('jy-output'); if (!text) return; navigator.clipboard.writeText(text).then(function() { var btn = document.querySelector('[onclick="jyCopyOutput()"]'); var orig = btn.textContent; btn.textContent = '✅ Copié !'; setTimeout(function() { btn.textContent = orig; }, 1800); }); } function jyDownload() { var text = jyV('jy-output'); if (!text) return; var ext = jyDir === 'json2yaml' ? '.yml' : '.json'; var blob = new Blob([text], { type: 'text/plain' }); var a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'converted' + ext; a.click(); URL.revokeObjectURL(a.href); } // ── Init ───────────────────────────────────────────────────────────────── jyUpdateLabels(); jyEl('jy-input').value = JY_SAMPLE_JSON; jyConvert(); jyStats(JY_SAMPLE_JSON, 'jy-input-info');