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:
| Feature | JSON | YAML | TOML |
|---|---|---|---|
| Primary Use Case | Web APIs, network IPC, machine serialization | Kubernetes manifests, CI/CD pipelines, Ansible | Application configs, Rust Cargo, Python PyProject |
| Comments Supported | No (strictly forbidden by spec) | Yes (#) | Yes (#) |
| Hierarchy Syntax | Braces {} and brackets [] | Significant whitespace and indentation | Key-value pairs with table headers [table] |
| Typing Rigor | Strings, numbers, booleans, null | Implicit type coercion with many edge cases | Explicit types (dates, times, integers, floats) |
| Multiline Strings | Escaped \n characters only | Literal (|) and folded (>) blocks | Triple-quoted strings (""") |
| Parsing Speed | Extremely fast | Slow (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:
1countries:
2 - US
3 - GB
4 - NOA 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:
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:
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}