YAML to JSON Converter: Convert YAML Files Online Instantly
Key Takeaways
- ▸YAML is a superset of JSON — every valid JSON document is valid YAML, but the reverse is not true
- ▸YAML's type coercion rules (the Norway Problem, boolean strings) are the #1 source of silent data corruption during conversion
- ▸Always use
yaml.safe_load()in Python —yaml.load()without a Loader is a remote code execution vulnerability - ▸Kubernetes accepts both YAML and JSON natively — the kubectl CLI converts YAML to JSON before sending to the API server
- ▸JSON parses 5–10× faster than YAML — for data interchange at scale, convert config YAML to JSON at build time
The Problem: Two Worlds That Need to Talk
Here is a scenario that plays out dozens of times a day in backend and DevOps workflows: a Kubernetes manifest or GitHub Actions workflow is written in YAML (as all Kubernetes and CI/CD configs are), but the tool consuming it — a validation script, a configuration management system, a REST API — expects JSON. Or the reverse: an API returns JSON, but the infrastructure-as-code tool consuming it expects YAML.
Converting between YAML and JSON is a constant need in modern software stacks. Docker Compose, Kubernetes, Ansible, GitHub Actions, AWS CloudFormation (YAML variant), Helm charts — all use YAML. APIs, databases, message queues, and most programming language data structures use JSON. The two formats dominate different layers of the stack, and they frequently need to communicate.
The conversion sounds trivial — and for simple files, it is. But YAML has features JSON cannot represent, YAML parsers have type coercion behaviors that silently corrupt data, and security vulnerabilities in YAML deserialization have been exploited in production systems. This guide covers the full picture.
For a quick conversion, use the BytePane YAML to JSON converter — paste your YAML, get JSON instantly in your browser. For understanding the underlying mechanics, read on.
YAML vs JSON: The Structural Differences
YAML 1.2 is officially a superset of JSON — every valid JSON document is valid YAML. But in practice, the two formats have very different design philosophies and syntactic rules:
| Feature | YAML | JSON | Conversion Impact |
|---|---|---|---|
| Comments | Yes (# comment) | No | Lost on conversion |
| Anchors & Aliases | Yes (&name / *name) | No | Dereferenced (duplicated) |
| Multi-document | Yes (--- separator) | No (NDJSON workaround) | Requires document splitting |
| Type coercion | Automatic (YES → true) | Explicit only | Silent data corruption risk |
| Binary data | Yes (!!binary tag) | No (use Base64 string) | Converted to Base64 string |
| Integer keys | Allowed | Strings only | Coerced to strings |
| Trailing commas | N/A (indentation-based) | Not allowed | No issue |
The structural differences matter less than the type coercion differences when it comes to data integrity. A comment being dropped is annoying but expected. Silently converting the string "NO" to the boolean false is a production bug.
The Norway Problem and Other YAML Type Traps
The single most dangerous thing about YAML-to-JSON conversion is YAML's type coercion rules. In YAML 1.1 (used by PyYAML before 6.0, and still the default in many libraries), a number of unquoted strings are automatically interpreted as booleans:
# YAML 1.1 boolean coercion — these all become true/false in PyYAML < 6.0
coerced_true: yes
also_true: YES
also_true_2: Yes
also_true_3: on
also_true_4: ON
also_true_5: true
coerced_false: no
also_false: NO # ← "NO" (country code for Norway) becomes false!
also_false_2: off
also_false_3: false
# JSON output (PyYAML 5.x):
# {
# "coerced_true": true,
# "coerced_false": false,
# "also_false": false ← NO is now false
# }This is the famous Norway Problem — a well-documented YAML 1.1 parsing quirk where the ISO 3166-1 alpha-2 country code for Norway ("NO") is silently parsed as false. It became notorious when it caused data corruption in systems where country codes were stored as unquoted YAML strings.
YAML 1.2 fixed this — only true and false (lowercase) are booleans. But many libraries still default to YAML 1.1. The fix is simple: quote all string values that could be misinterpreted.
# Safe YAML — explicit quoting prevents type coercion
country: "NO" # stays "NO", not false
status: "yes" # stays "yes", not true
port: "8080" # stays "8080" string, not integer 8080
version: "1.0" # stays "1.0" string, not float 1.0
# Or check your library's YAML version:
# Python: yaml.safe_load() with PyYAML >= 6.0 uses YAML 1.1 rules
# ruamel.yaml with version='1.2' uses strict YAML 1.2
import ruamel.yaml
yml = ruamel.yaml.YAML()
yml.version = (1, 2) # Enforce YAML 1.2 — "NO" stays "NO"The Octal Number Trap
Another silent type coercion that trips up developers: numbers that start with 0 in YAML 1.1 are parsed as octal. This is a direct consequence of YAML's POSIX shell heritage:
# YAML 1.1 octal parsing
file_permissions: 0755 # → integer 493 (0755 octal = 493 decimal)
mode: 0644 # → integer 420
# This is why Kubernetes file permission configs use quoted strings:
# spec.securityContext.runAsUser: "0755" — not the same as 0755!
# YAML 1.2 (Go's gopkg.in/yaml.v3, ruamel.yaml v1.2):
# 0755 stays as integer 755, not 493. Octal requires 0o755.
# Safe practice: always quote values that look like octal or hex
file_permissions: "0755" # Explicit string, no ambiguityYAML Anchors and Aliases: DRY Configs
One of YAML's most useful features for configuration files — and one that has no JSON equivalent — is anchors (&) and aliases (*). They let you define a value once and reference it multiple times:
# YAML with anchors — define once, reference everywhere
defaults: &defaults
image: node:20-alpine
restart: unless-stopped
environment:
NODE_ENV: production
LOG_LEVEL: info
services:
api:
<<: *defaults # Merge all defaults into api service
ports: ["3000:3000"]
worker:
<<: *defaults # Same defaults for worker
ports: []
command: node worker.jsWhen this YAML is converted to JSON, the anchors are dereferenced — the referenced content is fully copied to each alias location:
{
"defaults": {
"image": "node:20-alpine",
"restart": "unless-stopped",
"environment": {
"NODE_ENV": "production",
"LOG_LEVEL": "info"
}
},
"services": {
"api": {
"image": "node:20-alpine",
"restart": "unless-stopped",
"environment": { "NODE_ENV": "production", "LOG_LEVEL": "info" },
"ports": ["3000:3000"]
},
"worker": {
"image": "node:20-alpine",
"restart": "unless-stopped",
"environment": { "NODE_ENV": "production", "LOG_LEVEL": "info" },
"ports": [],
"command": "node worker.js"
}
}
}The JSON output is larger (the shared content is duplicated), but it is functionally identical. This is why Kubernetes and Docker Compose tooling can consume both YAML and JSON — they process YAML, dereference all anchors, and work with a flat JSON-equivalent data structure internally.
Converting YAML to JSON in Code
For one-off conversions, an online tool is fastest. For programmatic conversion in a pipeline or application, here are production-grade implementations in the three most common environments:
Python (PyYAML / ruamel.yaml)
import yaml
import json
import sys
def yaml_to_json(yaml_input: str, indent: int = 2) -> str:
"""
Convert YAML string to JSON string.
Uses safe_load to prevent arbitrary code execution.
"""
try:
# safe_load only processes basic YAML types
# NEVER use yaml.load() without Loader=yaml.SafeLoader
data = yaml.safe_load(yaml_input)
except yaml.YAMLError as e:
raise ValueError(f"Invalid YAML: {e}")
return json.dumps(data, indent=indent, ensure_ascii=False)
# From file
def convert_file(yaml_path: str, json_path: str) -> None:
with open(yaml_path, 'r', encoding='utf-8') as f:
yaml_content = f.read()
json_content = yaml_to_json(yaml_content)
with open(json_path, 'w', encoding='utf-8') as f:
f.write(json_content)
# From stdin (for shell pipelines)
if __name__ == '__main__':
yaml_input = sys.stdin.read()
print(yaml_to_json(yaml_input))
# CLI usage:
# python3 convert.py < config.yaml > config.json
# cat k8s-manifest.yaml | python3 convert.pyFor YAML 1.2 compliance (fixing the Norway Problem at the library level), use ruamel.yaml:
from ruamel.yaml import YAML
import json
def yaml_to_json_strict(yaml_input: str) -> str:
yml = YAML(typ='safe') # Safe mode — no Python-specific tags
yml.version = (1, 2) # YAML 1.2 — "NO" stays "NO"
import io
data = yml.load(io.StringIO(yaml_input))
return json.dumps(data, indent=2, ensure_ascii=False)
# ruamel.yaml also handles multi-document YAML:
def convert_multidoc(yaml_input: str) -> list:
yml = YAML(typ='safe')
documents = list(yml.load_all(io.StringIO(yaml_input)))
return [json.dumps(doc, indent=2) for doc in documents]Node.js (js-yaml)
// npm install js-yaml
import yaml from 'js-yaml';
import fs from 'fs/promises';
/**
* Convert YAML string to formatted JSON string.
* js-yaml defaults to YAML 1.2 behavior — correct boolean parsing.
*/
function yamlToJson(yamlInput: string, indent: number = 2): string {
try {
// yaml.load() in js-yaml is safe by default (no !!js/eval tags)
const data = yaml.load(yamlInput);
return JSON.stringify(data, null, indent);
} catch (err) {
if (err instanceof yaml.YAMLException) {
throw new Error(`YAML parse error at line ${err.mark?.line}: ${err.reason}`);
}
throw err;
}
}
// Process a Kubernetes manifest file
async function convertK8sManifest(inputPath: string, outputPath: string) {
const yamlContent = await fs.readFile(inputPath, 'utf-8');
// Handle multi-document YAML (multiple --- separated docs)
const docs = yaml.loadAll(yamlContent);
const jsonContent = JSON.stringify(docs, null, 2);
await fs.writeFile(outputPath, jsonContent, 'utf-8');
console.log(`Converted ${docs.length} documents to ${outputPath}`);
}
// Example: validate a converted config schema
import Ajv from 'ajv';
const ajv = new Ajv();
async function validateYamlConfig(yamlPath: string, schemaPath: string) {
const [yamlContent, schemaContent] = await Promise.all([
fs.readFile(yamlPath, 'utf-8'),
fs.readFile(schemaPath, 'utf-8'),
]);
const data = yaml.load(yamlContent);
const schema = JSON.parse(schemaContent);
const validate = ajv.compile(schema);
const valid = validate(data);
if (!valid) {
console.error('Validation errors:', validate.errors);
process.exit(1);
}
console.log('Config valid ✓');
}Go (gopkg.in/yaml.v3)
// go get gopkg.in/yaml.v3
package main
import (
"encoding/json"
"fmt"
"os"
"gopkg.in/yaml.v3"
)
// YAMLToJSON converts a YAML byte slice to a JSON byte slice.
// gopkg.in/yaml.v3 uses YAML 1.2 — correct boolean/octal handling.
func YAMLToJSON(yamlData []byte) ([]byte, error) {
// Unmarshal YAML into a generic interface{}
var yamlObj interface{}
if err := yaml.Unmarshal(yamlData, &yamlObj); err != nil {
return nil, fmt.Errorf("yaml parse: %w", err)
}
// yaml.v3 unmarshals maps as map[string]interface{}
// which is directly JSON-serializable
jsonData, err := json.MarshalIndent(yamlObj, "", " ")
if err != nil {
return nil, fmt.Errorf("json marshal: %w", err)
}
return jsonData, nil
}
func main() {
yamlData, err := os.ReadFile("config.yaml")
if err != nil {
fmt.Fprintf(os.Stderr, "read file: %v\n", err)
os.Exit(1)
}
jsonData, err := YAMLToJSON(yamlData)
if err != nil {
fmt.Fprintf(os.Stderr, "convert: %v\n", err)
os.Exit(1)
}
fmt.Println(string(jsonData))
}
// Note: yaml.v2 uses YAML 1.1 (Norway Problem exists)
// Always use yaml.v3 for new code.Command-Line Conversion: yq and Python One-Liners
For shell scripting and CI/CD pipelines, you often need YAML-to-JSON conversion without writing code. There are two reliable options:
yq — The YAML Command-Line Processor
yq (Mike Farah's Go implementation, not the older Python version) is the Swiss Army knife for YAML on the command line. It follows jq's filter syntax and handles multi-document YAML correctly:
# Install: brew install yq OR go install github.com/mikefarah/yq/v4@latest
# Basic conversion
yq -o json config.yaml
# Pretty-printed JSON
yq -o json -I 2 config.yaml
# Multi-document YAML → JSON array
yq -o json '. | [.]' multi-doc.yaml
# Convert in pipeline (Kubernetes manifest → JSON)
kubectl get deployment my-app -o yaml | yq -o json
# Extract specific field and convert
yq '.spec.template.spec.containers[0]' deployment.yaml | yq -o json
# Process all YAML files in directory
for f in configs/*.yaml; do
yq -o json "$f" > "output/$(basename "$f" .yaml).json"
donePython One-Liner (No Dependencies)
# Python is on virtually every Unix/macOS system — no install needed
python3 -c "import sys, yaml, json; json.dump(yaml.safe_load(sys.stdin), sys.stdout, indent=2)" < input.yaml
# Read from file, write to file
python3 -c "
import yaml, json
with open('input.yaml') as f:
data = yaml.safe_load(f)
with open('output.json', 'w') as f:
json.dump(data, f, indent=2)
"
# Handle multi-document YAML
python3 -c "
import yaml, json, sys
docs = list(yaml.safe_load_all(sys.stdin))
json.dump(docs, sys.stdout, indent=2)
" < multi-doc.yamlSecurity Warning: YAML Deserialization Attacks
This deserves its own section because it is a real vulnerability that has been exploited in production Ruby on Rails applications, Python services, and Java microservices.
YAML parsers that support the full YAML spec allow type tags like !!python/object/apply or !!java.lang.Runtime. When a parser processes YAML with these tags, it can instantiate arbitrary objects and execute code:
# Malicious YAML — DO NOT process this with yaml.load() / yaml.full_load()
# This executes "rm -rf /tmp/evil" when parsed by PyYAML without SafeLoader
evil: !!python/object/apply:subprocess.check_output
- ["rm", "-rf", "/tmp/evil"]
# CVE-2017-18342 (PyYAML) — arbitrary code execution via YAML
# CVE-2021-25326 (Ruby psych) — similar vector in RubyThe rules for safe YAML processing are non-negotiable:
- Python: Always use
yaml.safe_load(). Never useyaml.load()withoutLoader=yaml.SafeLoader. - Ruby: Use
Psych.safe_load()instead ofYAML.load(). - Java (SnakeYAML): Use
new Yaml(new SafeConstructor()). - Node.js (js-yaml):
yaml.load()is safe by default (no arbitrary object instantiation) — but avoidyaml.load(input, { schema: yaml.DEFAULT_SCHEMA })with untrusted input. - Go:
gopkg.in/yaml.v3is safe by default — it does not support arbitrary type instantiation.
For input validation before conversion, use BytePane's JSON Formatter to verify the output structure is what you expect before consuming it in downstream systems.
Real-World Use Cases: Why Developers Convert Between Formats
1. Kubernetes Manifest Validation
Kubernetes manifests are always YAML. But JSON Schema validation tools — including many CI/CD pipeline validators — expect JSON. Converting YAML manifests to JSON before validation is a standard step in Kubernetes GitOps pipelines:
# .github/workflows/validate-manifests.yml
steps:
- name: Validate Kubernetes manifests
run: |
for f in k8s/**/*.yaml; do
# Convert to JSON for schema validation
json=$(yq -o json "$f")
# Validate against Kubernetes JSON Schema
echo "$json" | ajv validate -s k8s-schema.json -d -
done2. OpenAPI / Swagger Spec Conversion
OpenAPI 3.x specifications can be written in either YAML or JSON. Many teams write in YAML (more readable, supports comments), but API mocking tools, SDK generators, and documentation platforms often require JSON:
# Convert OpenAPI YAML to JSON for Postman/Insomnia import
yq -o json openapi.yaml > openapi.json
# Or with js-yaml in a build script
import yaml from 'js-yaml';
import { readFileSync, writeFileSync } from 'fs';
const spec = yaml.load(readFileSync('openapi.yaml', 'utf-8'));
writeFileSync('openapi.json', JSON.stringify(spec, null, 2));3. GitHub Actions Configuration Debugging
GitHub Actions workflows are YAML. When debugging complex matrix configurations or conditional expressions, converting to JSON can make the structure easier to reason about:
# Extract and inspect the matrix configuration
yq '.jobs.build.strategy.matrix' .github/workflows/ci.yml | yq -o json4. Config File Preprocessing
Some teams maintain application configuration in YAML for readability (comments, anchors, multiline strings) but convert to JSON at build/deploy time for parsing performance. JSON parsers are 5–10× faster than YAML parsers, and since config files are read on every application startup, the difference adds up at scale.
For reference on understanding format trade-offs, see our comparison of JSON vs YAML vs XML covering when each format is the right tool.
Frequently Asked Questions
Can all YAML be converted to JSON?
Not always. YAML has features JSON cannot represent: comments (stripped on conversion), anchors and aliases (dereferenced), multi-document streams (need splitting), and binary data types. Well-formed YAML that avoids these features converts to JSON losslessly. The most common lossy conversion is comments — always keep your original YAML source, not just the converted JSON.
Why do Kubernetes and Helm use YAML instead of JSON?
Kubernetes manifests use YAML because YAML supports comments and multi-document files, making configuration easier to annotate and reason about. Kubernetes actually accepts both YAML and JSON — kubectl converts YAML to JSON before sending to the API server. Helm templates use YAML with Go templating layered on top, enabling DRY configuration with anchors and variables.
What is the Norway Problem in YAML?
The Norway Problem is a YAML 1.1 parsing bug where the country code "NO" is interpreted as the boolean false. "YES", "ON", "OFF" are similarly parsed as booleans. YAML 1.2 fixed this — only lowercase "true"/"false" are booleans. Many libraries (PyYAML before 6.0) still default to YAML 1.1. Fix: quote bare strings, or use a YAML 1.2-compliant library like ruamel.yaml.
Does YAML to JSON conversion preserve data types?
Depends on the parser's type resolution. Strings that look like numbers ("1.0") may be parsed as floats. Strings that look like booleans ("true", "yes") become booleans in YAML 1.1 parsers. Quote all string values in YAML that could be misinterpreted. The YAML spec's type coercion rules are the most frequent source of subtle bugs in configuration pipelines.
What happens to YAML anchors when converting to JSON?
YAML anchors (&name) and aliases (*name) create references to shared values. JSON has no equivalent reference mechanism. Converters dereference anchors — the shared value is duplicated at each alias location. Output is functionally equivalent but larger. This is expected behavior; keep the original YAML source if you need the DRY reference structure.
Is YAML faster to parse than JSON?
No. JSON is 5–10× faster to parse than YAML. JSON parsing is a well-solved problem — V8's JSON.parse() is implemented in highly optimized C++. YAML parsers handle a more complex grammar: indentation tracking, type coercion, anchors, multi-document support. For data interchange at scale, JSON is the right choice. YAML's advantages are human readability and authoring ergonomics, not performance.
How do I convert YAML to JSON on the command line?
With Python (on most Unix/macOS systems): python3 -c "import sys, yaml, json; json.dump(yaml.safe_load(sys.stdin), sys.stdout, indent=2)" < input.yaml. With yq (a dedicated YAML CLI tool): yq -o json input.yaml. With Node.js: install js-yaml and use yaml.load() then JSON.stringify().
What is the difference between yaml.safe_load and yaml.full_load?
yaml.safe_load() (PyYAML) only processes basic YAML types: strings, numbers, lists, dicts, booleans, null. yaml.full_load() also processes Python-specific YAML tags like !!python/object, which can execute arbitrary code. Always use safe_load when processing YAML from untrusted sources — PyYAML deserialization attacks are a real, documented vulnerability class with assigned CVEs.
Convert YAML to JSON Instantly
Paste your YAML into the BytePane converter and get clean, formatted JSON in your browser — no server uploads, no size limits. Also available: JSON to YAML, JSON formatting and validation, and more.
Related Articles
JSON vs YAML vs XML: Which Format Should You Use?
Honest format comparison covering readability, tooling, and real-world use cases.
What Is JSON? A Developer's Guide
JSON syntax, RFC 8259, parsing, and when to switch to a different format.
JSON Formatting Guide
How to structure clean, readable JSON for APIs and config files.
JSON to CSV Converter
Flatten nested JSON to CSV: dot notation, array explosion, and streaming.