Markdown (LLM)
Initializing...

JSON to YAML & TOML Converter

Convert bidirectionally between JSON, YAML, and TOML. Pretty-print, validate, and minify configurations client-side in your browser.

Target Format:
Input Parsing:
Presets:
Source Input Auto
0 chars
Converted Output YAML
0 chars

Converting Configurations Across JSON, YAML, and TOML

Engineering workflows routinely require transforming configuration structures across formats. Kubernetes controllers and Helm charts expect YAML, web service APIs consume JSON, and Cargo or pyproject files rely on TOML.

This converter runs Go’s standard ecosystem parsers (encoding/json, gopkg.in/yaml.v3, and github.com/pelletier/go-toml/v2) directly in the browser via WebAssembly to ensure identical syntax compatibility with backend tooling.


Comparing JSON, YAML, and TOML

Each configuration format was created to solve different trade-offs across machine speed, human readability, and document hierarchy:

FeatureJSONYAMLTOML
Primary Use CaseWeb APIs, network IPC, machine serializationKubernetes manifests, CI/CD pipelines, AnsibleApplication configs, Rust Cargo, Python PyProject
Comments SupportedNo (strictly forbidden by spec)Yes (#)Yes (#)
Hierarchy SyntaxBraces {} and brackets []Significant whitespace and indentationKey-value pairs with table headers [table]
Typing RigorStrings, numbers, booleans, nullImplicit type coercion with many edge casesExplicit types (dates, times, integers, floats)
Multiline StringsEscaped \n characters onlyLiteral (|) and folded (>) blocksTriple-quoted strings (""")
Parsing SpeedExtremely fastSlow (complex state machine)Moderate

Subtle Production Gotchas Across Formats

1. The YAML Norway Problem

YAML 1.1 defines y, Y, yes, Yes, YES, n, N, no, No, and NO as boolean values. If your configuration includes a country code list:

yaml
1countries:
2  - US
3  - GB
4  - NO

A YAML 1.1 parser will parse NO as boolean false instead of the string "NO". In JSON and TOML, strings must always be quoted, completely eliminating this class of silent type conversion bugs.

2. Billion Laughs and Anchor Bomb Attacks

YAML supports reference anchors (&anchor) and aliases (*anchor). An attacker can define recursive alias expansions that consume gigabytes of memory upon parsing:

yaml
1a: &a ["lol","lol","lol","lol","lol"]
2b: &b [*a,*a,*a,*a,*a]
3c: &c [*b,*b,*b,*b,*b]

When writing Go backends that ingest untrusted YAML files, always configure resource limits or reject manifests containing excessive anchor references.

3. Top-Level Array Limitations in TOML

TOML requires every document to be a key-value table. Unlike JSON or YAML, a TOML file cannot represent a bare list or array at the document root. Converting an array-first JSON payload (e.g. [{"id": 1}, {"id": 2}]) directly to TOML requires wrapping the items inside an outer object key.


Converting Between Formats in Go

Here is how to convert a configuration payload between JSON, YAML, and TOML in pure Go using standard ecosystem libraries:

go
 1package main
 2
 3import (
 4	"bytes"
 5	"encoding/json"
 6	"fmt"
 7
 8	"github.com/pelletier/go-toml/v2"
 9	"gopkg.in/yaml.v3"
10)
11
12// YAMLToJSON parses arbitrary YAML and emits formatted JSON
13func YAMLToJSON(yamlData []byte) ([]byte, error) {
14	var raw any
15	if err := yaml.Unmarshal(yamlData, &raw); err != nil {
16		return nil, fmt.Errorf("failed to parse YAML: %w", err)
17	}
18
19	// Normalize interface maps so json.Marshal accepts them
20	normalized := cleanMapKeys(raw)
21	return json.MarshalIndent(normalized, "", "  ")
22}
23
24// JSONToTOML parses JSON and encodes to TOML tables
25func JSONToTOML(jsonData []byte) ([]byte, error) {
26	var raw map[string]any
27	if err := json.Unmarshal(jsonData, &raw); err != nil {
28		return nil, fmt.Errorf("failed to parse JSON: %w", err)
29	}
30
31	var buf bytes.Buffer
32	if err := toml.NewEncoder(&buf).Encode(raw); err != nil {
33		return nil, fmt.Errorf("failed to encode TOML: %w", err)
34	}
35	return buf.Bytes(), nil
36}
37
38func cleanMapKeys(val any) any {
39	switch v := val.(type) {
40	case map[any]any:
41		clean := make(map[string]any, len(v))
42		for k, item := range v {
43			clean[fmt.Sprintf("%v", k)] = cleanMapKeys(item)
44		}
45		return clean
46	case []any:
47		for i, item := range v {
48			v[i] = cleanMapKeys(item)
49		}
50		return v
51	default:
52		return v
53	}
54}