What is YAML and why convert to JSON?
YAML ("YAML Ain't Markup Language") is a human-friendly data serialization format defined in the YAML 1.2.2 specification. It is the dominant format for configuration files in the cloud-native ecosystem: Kubernetes manifests, Docker Compose, GitHub Actions workflows, GitLab CI, Ansible playbooks, Helm charts, OpenAPI / Swagger specs, AWS CloudFormation, and Cargo / Cabal config files. The reason: YAML is comment-friendly, indentation-based, and reads like English. JSON, while more strict and machine-friendly, is verbose for humans to write — every key needs quotes, no comments allowed, brackets everywhere.
Why convert YAML ⇄ JSON? Three common reasons:
- API consumption — your config is in YAML, but the tool you're integrating with expects JSON (most REST APIs, GraphQL, NoSQL databases).
- Validation and schema checks — JSON Schema validators are far more mature than YAML schema tools. Convert YAML to JSON, validate, then back.
- Debugging — when a YAML file breaks, converting to JSON often reveals the actual structure (especially the dreaded "Norway problem" where
NObecomes booleanfalse).
JSON and YAML are both subsets of the same conceptual data model: scalars (strings, numbers, booleans, null), sequences (arrays), and mappings (objects). YAML 1.2 was specifically designed so that every JSON document is valid YAML. The reverse is not true — YAML has features (anchors, multi-document streams, custom tags) that JSON cannot represent.
YAML vs JSON — feature-by-feature comparison
| Feature | YAML 1.2 | JSON (RFC 8259) |
|---|---|---|
| Comments | # comment on any line | Not supported (use JSONC for comments) |
| Trailing commas | Not applicable (no commas in block style) | Forbidden |
| Quoted keys | Optional | Required (always double quotes) |
| String quoting | Optional, single, or double quotes | Double quotes only |
| Multi-line strings | Yes — | (literal) and > (folded) | Single line only (use \n escapes) |
Anchors & aliases (&, *) | Yes — DRY config via reusable nodes | No |
Multi-document streams (---) | Yes — multiple docs per file | No (one root value) |
| Custom tags / types | Yes — !!str, !Ref, custom | No |
| Indentation-significant | Yes — spaces only (no tabs) | No (whitespace ignored) |
| Parser ambiguity | Higher — Norway problem, octal numbers | Minimal — strict grammar |
| File size (typical) | ~30–40% smaller than equivalent JSON | Larger due to required punctuation |
| Best for | Human-edited config (k8s, CI, Compose) | API payloads, machine-to-machine data |
Rule of thumb: humans should edit YAML; machines should exchange JSON. The conversion is lossless when going from JSON → YAML (because JSON is a subset). It is almost lossless from YAML → JSON — features like anchors get expanded inline, comments are stripped, and custom tags are flattened to plain values.
YAML syntax — what every developer should know
Scalars (the basic types)
# Plain scalars (no quotes — YAML guesses the type)
name: Anees # string
age: 30 # integer
height: 5.9 # float
active: true # boolean
nickname: null # null (also: ~)
phone: "+1 555 1234" # explicitly string (quotes prevent number parsing)
# Multi-line strings
literal: | # preserves newlines
Line 1
Line 2
folded: > # folds newlines to spaces
Line 1
continues here
Sequences (arrays)
# Block style (preferred for readability)
fruits:
- apple
- banana
- cherry
# Flow style (compact, JSON-like)
fruits: [apple, banana, cherry]
# Nested sequence
matrix:
- [1, 2, 3]
- [4, 5, 6]
Mappings (objects)
# Block style
user:
name: Anees
age: 30
email: anees@example.com
# Flow style
user: {name: Anees, age: 30, email: anees@example.com}
# Mappings of sequences
team:
developers:
- alice
- bob
managers:
- carol
Anchors and aliases — DRY config
# Define an anchor with &
defaults: &defaults
timeout: 30
retries: 3
region: us-east-1
# Reuse with *
production:
<<: *defaults # merge key — inherit all defaults
region: us-west-2 # override one field
staging:
<<: *defaults
Multi-document streams
# A single .yaml file can contain multiple documents,
# separated by --- (and optionally ended with ...)
apiVersion: v1
kind: ConfigMap
metadata: { name: app-config }
---
apiVersion: v1
kind: Secret
metadata: { name: app-secret }
---
# common in kubectl apply -f and Helm templates
The infamous YAML pitfalls
1. The Norway problem (YAML 1.1 only — but it bites)
YAML 1.1 treats NO, YES, ON, OFF, true, false (in any case) as booleans. So country: NO becomes {"country": false}, not {"country": "NO"}. YAML 1.2 fixed this — only true/false (lowercase) are booleans now. But many parsers default to YAML 1.1 for backward compatibility. Fix: always quote string values that look like booleans: country: "NO".
2. Tabs are forbidden
YAML allows only spaces for indentation. Tabs in indentation cause parse errors. Looks fine in editors that render tabs as spaces. Fix: configure your editor to use spaces; lint with yamllint.
3. Octal numbers
In YAML 1.1, version: 010 is parsed as octal 8, not the string "010" or the integer 10. YAML 1.2 fixed this (octals require 0o prefix), but legacy parsers still bite. Fix: quote leading-zero values: version: "010".
4. Mixed indentation widths
Some sub-blocks use 2 spaces; others use 4. Parsers handle this consistently as long as siblings match, but it's a style nightmare and can cause parser disagreements between strict and lenient implementations.
5. Numbers vs strings ambiguity
version: 1.0→ number 1.0 (the trailing zero is lost)version: "1.0"→ string "1.0"price: 1,000→ string "1,000" (comma makes it non-numeric)id: 1234567890→ integer (might overflow JS Number precision at 2^53)
6. Empty values
name: (with nothing after) parses as null, not "". To get an empty string, use name: "" or name: ''.
7. Anchors get expanded on conversion
Convert YAML with anchors to JSON, then back, and you'll lose the anchors — they're inlined. The result has the same data but loses the DRY abstraction.
yamllint in CI to catch these issues before they cause production outages. The default config catches all the above.
YAML/JSON conversion in 8 programming languages
Node.js (js-yaml)
import yaml from 'js-yaml';
// YAML → JSON object
const data = yaml.load(yamlString);
// JSON object → YAML
const yamlOut = yaml.dump(data, { indent: 2, lineWidth: 120 });
// Multi-document YAML stream
const docs = yaml.loadAll(yamlString); // returns array of docs
Python (PyYAML)
import yaml
import json
# YAML → dict (use safe_load to disable arbitrary code execution)
data = yaml.safe_load(yaml_string)
# dict → YAML
yaml_out = yaml.dump(data, default_flow_style=False, sort_keys=False)
# Multi-document
for doc in yaml.safe_load_all(yaml_string):
print(doc)
# YAML → JSON
print(json.dumps(yaml.safe_load(yaml_string), indent=2))
Python (ruamel.yaml — preserves comments)
from ruamel.yaml import YAML
yaml = YAML()
yaml.preserve_quotes = True
# Round-trips with comments and ordering preserved
with open('config.yml') as f:
data = yaml.load(f)
data['new_key'] = 'value'
with open('config.yml', 'w') as f:
yaml.dump(data, f) # Comments survive!
Go (gopkg.in/yaml.v3)
import "gopkg.in/yaml.v3"
type Config struct {
Name string `yaml:"name"`
Servers []string `yaml:"servers"`
}
var c Config
yaml.Unmarshal([]byte(yamlData), &c)
// Encode
out, _ := yaml.Marshal(c)
Rust (serde_yaml)
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Config { name: String, servers: Vec<String> }
// YAML → struct
let c: Config = serde_yaml::from_str(&yaml_str)?;
// struct → YAML
let yaml = serde_yaml::to_string(&c)?;
Ruby
require 'yaml'
require 'json'
# YAML → Hash (safe_load is Ruby's recommended)
data = YAML.safe_load(yaml_str)
# Hash → YAML
yaml_out = data.to_yaml
# Multi-document stream
YAML.load_stream(yaml_str) { |doc| puts doc }
# YAML → JSON
puts JSON.pretty_generate(YAML.safe_load(yaml_str))
PHP (Symfony Yaml)
// composer require symfony/yaml
use Symfony\Component\Yaml\Yaml;
$data = Yaml::parse($yamlString);
$yaml = Yaml::dump($data, 4); // 4-space indent
// PHP built-in (PECL yaml extension)
$data = yaml_parse($yamlString);
$yaml = yaml_emit($data);
Bash (yq + jq)
# yq is "jq for YAML" — install via brew/snap/apt
# YAML → JSON
yq -o=json '.' config.yml
# JSON → YAML
yq -P '.' data.json
# Edit a YAML field in place
yq -i '.image.tag = "v1.2.3"' deployment.yml
# Combined with jq for complex queries
yq -o=json . k8s.yml | jq '.spec.containers[].image'
Real-world use cases
Kubernetes manifests
Every kubectl apply -f file.yaml command parses YAML into JSON internally before sending it to the Kubernetes API server. The API itself is JSON-only. Your local kubectl get pod -o yaml works in reverse — JSON in, YAML out for human reading. Tools like kustomize and helm manipulate YAML to produce final manifests.
Docker Compose
Compose files are pure YAML. Converting them to JSON is useful when programmatically generating Compose configurations from another tool, or when building CI matrices that test multiple configurations.
GitHub Actions workflows
Workflows are YAML, but the GitHub API serves them as JSON. Programmatic generation (e.g. dynamically creating a workflow from a database of jobs) usually goes via JSON, then dumps to YAML for the final .github/workflows/*.yml file.
OpenAPI / Swagger specs
OpenAPI 3.x supports both YAML and JSON. The YAML form is preferred for editing (comments, multi-line); the JSON form is what you ship with your SDK or pipe into validation tools.
AWS CloudFormation & Helm charts
Both rely heavily on YAML's anchor & alias features for DRY templates. When converting to JSON, anchors expand inline — you lose abstraction but gain machine-friendliness.
Best YAML to JSON converter for 2026 — what to compare
Search results for "yaml to json", "yaml converter online", and "convert kubernetes yaml to json" return many tools but most fail on real-world YAML: they don't handle anchors and aliases (DRY config patterns universal in Helm and Docker Compose), multi-doc streams (--- separators in kubectl apply -f bundles), or YAML 1.2-vs-1.1 differences (the famous Norway problem where NO becomes false). Here is how the most-used YAML/JSON converters compare in 2026:
| Tool | Bidirectional | Anchors / aliases / multi-doc | YAML version | Browser-only | Cost |
|---|---|---|---|---|---|
| FreeDevTool YAML ⇄ JSON | Yes | All three supported | YAML 1.2 (no Norway problem) | Yes | Free |
| onlineyamltools.com | Yes | Anchors only | YAML 1.1 | Server-side | Free, ad-funded |
| convertsimple.com/convert-yaml-to-json | One direction | Limited | YAML 1.1 | Server-side | Free, ad-heavy |
yq CLI (Mike Farah) | Yes (both directions) | Full | YAML 1.2 | Local install | Free, OSS |
npm js-yaml + JSON.stringify | Yes (programmatic) | Full | YAML 1.2 | Local install | Free, OSS |
Python ruamel.yaml | Yes (programmatic) | Full + comments preserved | YAML 1.2 | Local install | Free, OSS |
How do I convert a Kubernetes YAML manifest to JSON without uploading it?
Paste the manifest into the YAML pane on this page. The browser-side js-yaml parser handles all Kubernetes-specific patterns: multi-document streams (a single kubectl apply file often has Deployment + Service + Ingress separated by ---), Helm-rendered anchors and aliases, and CRDs with custom !Tag markers. Output is valid JSON ready for kubectl apply -f - with the --server-side flag, or for ingestion into Pulumi / CDK8s / Terraform kubernetes_manifest resources. Why client-side matters for k8s configs: production manifests routinely contain Service environment variables, ConfigMap references to internal hostnames, secret-sealed values, and ImagePullSecret credentials. Even a "test" manifest may leak real cluster topology. This page never uploads — verify in DevTools Network tab.
What's the difference between YAML 1.1, YAML 1.2, and JSON?
| Feature | YAML 1.1 (2005) | YAML 1.2 (2009+) | JSON (2017 RFC 8259) |
|---|---|---|---|
| Boolean coercion (Norway problem) | NO / OFF → false | Only true / false | Only true / false |
| Numeric formats | Octal via 0o755 AND 0755 | Octal only via 0o755 | Decimal only |
| Strict superset of JSON | No | Yes (every JSON is valid YAML) | N/A |
| Comments | Yes (#) | Yes (#) | No |
| Anchors / aliases | Yes | Yes | No |
| Multi-doc streams | Yes (---) | Yes (---) | No |
This converter uses a YAML 1.2 parser — which means country: NO stays as the string "NO" (not coerced to false). If you're maintaining legacy Ansible playbooks (still YAML 1.1 by default in Ansible 2.x), explicitly quote ambiguous values: country: "NO". Most modern tools (Kubernetes, Docker Compose v3+, GitHub Actions) use YAML 1.2.
YAML to JSON converter alternative to onlineyamltools.com — 4 reasons developers switched
- Browser-only, no server upload. onlineyamltools and convertsimple POST your YAML to a server. Production k8s manifests, Docker Compose configs, and GitHub Actions workflows often contain secrets — keep them in-browser.
- YAML 1.2 spec compliance, not 1.1 quirks. Avoids the Norway problem, octal-number ambiguity, and other YAML 1.1 footguns that bite real configs.
- Anchors, aliases, and multi-doc streams. Most online converters silently flatten anchors or drop documents past the first
---. This tool round-trips Helm, Compose, and bundled k8s manifests correctly. - No ads, no popups. Free YAML converters indexed by Google almost universally inject ads or rate-limit anonymous use. This page has neither.
Pair the YAML to JSON converter with the JSON Formatter for pretty-printing the output, the JSON to CSV Converter for spreadsheet exports, the XML Formatter for legacy XML configs, and the Encoding Tools hub for the broader transform toolkit.
YAML best practices
- Always quote string values that look like booleans, numbers, or dates.
country: "NO",version: "1.0",id: "01234". - Configure your editor for spaces, not tabs. Add
.editorconfigwithindent_style = spacefor*.ymland*.yaml. - Use
yamllintin CI. Catches indentation errors, trailing whitespace, line length, document start markers — fast, deterministic, low-overhead. - Use
safe_load, neverload. Python'syaml.loadcan execute arbitrary code (CVE-2017-18342). Always usesafe_loadfor untrusted input. - Don't store secrets in YAML. Use a secret manager (AWS Secrets Manager, Vault, Sealed Secrets, sops). Reference at runtime, never commit plaintext.
- Pick YAML 1.2 parsers when possible. They fix the Norway problem, octal-number gotchas, and other ambiguities.
js-yaml >= 4,ruamel.yaml, and Go'syaml.v3are 1.2. - Validate with JSON Schema. JSON Schema works on YAML too (after parsing). Catches type errors, missing required fields, and unexpected properties before deployment.
- Use
kubevalorkubeconformfor Kubernetes YAMLs. They validate against the actual K8s OpenAPI schema for your cluster version.