← Back to Blog

TOML vs YAML vs JSON: Pick the Right Config Format (2026)

Every developer has strong opinions about config file formats. JSON is universal but noisy. YAML is expressive but dangerously quirky. TOML is clean but less known. This guide breaks down all three with real examples so you can make the right choice for your project.

Why Config Format Choice Matters

The configuration format you choose affects every developer who works on the project. A poorly chosen format leads to frustrating indentation errors (YAML), verbose boilerplate (JSON), or onboarding friction when team members are unfamiliar with the syntax (TOML). More importantly, some formats have subtleties that cause real bugs: YAML's implicit type coercion has famously broken Kubernetes manifests and Ansible playbooks in production.

The three dominant formats each occupy a different position on the tradeoff curve between strictness, readability, and expressive power. Understanding those tradeoffs is more useful than any blanket recommendation.

The Same Config in All Three Formats

Before diving into pros and cons, here is the same application config expressed in all three formats so you can compare them directly:

JSON

{
  "app": {
    "name": "myapp",
    "version": "1.2.0",
    "debug": false
  },
  "database": {
    "host": "localhost",
    "port": 5432,
    "name": "mydb"
  },
  "allowed_hosts": ["localhost", "127.0.0.1"],
  "log_level": "info"
}

YAML

app:
  name: myapp
  version: "1.2.0"   # quoted to prevent YAML treating as float
  debug: false

database:
  host: localhost
  port: 5432
  name: mydb

allowed_hosts:
  - localhost
  - 127.0.0.1

log_level: info

TOML

[app]
name = "myapp"
version = "1.2.0"
debug = false

[database]
host = "localhost"
port = 5432
name = "mydb"

allowed_hosts = ["localhost", "127.0.0.1"]
log_level = "info"

All three represent the same data. The differences in verbosity, quoting requirements, and structure are immediately apparent.

JSON: Universal but Verbose

JSON (JavaScript Object Notation) is the lingua franca of data exchange. Every language has a built-in or standard-library JSON parser. Every API uses it. Every developer knows it. For configuration, however, JSON has significant drawbacks:

  • No comments. You cannot explain why a value is set the way it is. This is the most-cited frustration with JSON configs.
  • Trailing commas are invalid. Adding an item to the last element of an array or object requires editing two lines, and forgetting the comma causes a parse error.
  • Verbose quoting. Every key must be double-quoted. This adds noise when reading and editing large configs.
  • No multi-line strings. Embedding a multi-line script or template in JSON requires ugly escaped newlines.

Use JSON when: the config is consumed by a JavaScript/Node.js application (package.json, tsconfig.json), when it is also used as an API request/response body, or when maximum parser compatibility across languages is required.

YAML: Expressive but Treacherous

YAML is the dominant format for DevOps tooling: Kubernetes, Docker Compose, GitHub Actions, GitLab CI, Ansible, and Helm all use it. Its indentation-based syntax is compact and readable for nested structures. It supports comments, multi-line strings, anchors, and references. But YAML has a well-documented problem: implicit type coercion.

Consider this YAML:

country: NO      # Parsed as boolean false in YAML 1.1
version: 1.10    # Parsed as float 1.1, not the string "1.10"
port: 080        # Parsed as octal 64 in some parsers
enabled: yes     # Parsed as boolean true

This behavior has caused production incidents. A Kubernetes ConfigMap with a value of NO for a country code will silently become the boolean false. YAML 1.2 (used by newer parsers) fixes most of these issues, but parser version inconsistency remains a real risk.

YAML also requires precise indentation. A single stray space can change the meaning of a document entirely, and the error messages from YAML parsers are often unhelpful.

Use YAML when: the ecosystem requires it (Kubernetes, Docker Compose, GitHub Actions, Helm). YAML is the standard for infrastructure-as-code tooling and that convention is worth following even with its quirks.

TOML: Explicit and Predictable

TOML (Tom's Obvious, Minimal Language) was designed specifically to be a config file format, not a data serialization format. It takes the best parts of INI files and adds proper types, arrays, and nested tables. TOML is the config format for Rust's Cargo (Cargo.toml), Python packaging (pyproject.toml), Hugo, and many other modern tools.

Key TOML strengths:

  • Explicit types. true is a boolean, "true" is a string, 1.0 is a float. No surprises.
  • Comments. # comments are supported anywhere.
  • Native datetime type. 2026-03-26T12:00:00Z is a first-class type, not just a string.
  • Readable section headers. [database] sections are visually clear and do not rely on indentation.
# pyproject.toml example
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
log_level = "INFO"

[tool.mypy]
strict = true
ignore_missing_imports = false

[[tool.mypy.overrides]]
module = "third_party.*"
ignore_missing_imports = true

The [[double bracket]] syntax defines an array of tables - a feature with no clean equivalent in JSON or YAML.

Use TOML when: writing application config files that developers edit directly, especially for Rust, Python, or Go projects. TOML's explicitness makes it the safest choice for configs that will be hand-edited over time.

Side-by-Side Comparison

FeatureJSONYAMLTOML
CommentsNoYes (#)Yes (#)
Trailing commasNoN/AYes
Implicit type coercionNoYes (YAML 1.1)No
Multi-line stringsEscaped onlyYes (|, >)Yes (triple-quote)
Dates as native typeNo (strings)YesYes
Anchors/aliasesNoYesNo
Parser ubiquityUniversalVery commonGrowing
Primary use caseAPIs, npm, tsconfigK8s, Docker, CI/CDApp config, Cargo, pyproject

Convert Between JSON and YAML Instantly

Need to convert a YAML config to JSON or vice versa? Our free converter handles it in your browser with no data sent to any server.

Open JSON ↔ YAML Converter

Step-by-Step: Choosing the Right Format

  1. Is the format dictated by the ecosystem? If you are writing a Kubernetes manifest, GitHub Actions workflow, or Docker Compose file, use YAML - there is no choice. If you are writing a package.json or tsconfig.json, use JSON.
  2. Will humans edit this file frequently? If yes, prefer TOML or YAML. Both support comments, which are essential for maintainable config files. JSON without comments makes it very hard to document why a value is set a certain way.
  3. Does your team know the format? TOML has a learning curve for developers unfamiliar with it. If your team knows YAML well and the file is not safety-critical, YAML may be the pragmatic choice even if TOML would be technically superior.
  4. Do you need to serialize and deserialize programmatically? JSON is the safest choice for data that crosses system boundaries or is consumed by APIs. Its strict spec and universal parser support minimize compatibility issues.
  5. Do you need anchors and references? YAML anchors allow reusing a block of config in multiple places. If your config has significant repetition, YAML's anchor/alias feature (&anchor / *alias) can eliminate it. TOML and JSON have no equivalent.

YAML Pitfalls to Avoid

If you are using YAML, here are the most common traps:

  • Always quote version strings: version: "1.10" not version: 1.10
  • Always quote country codes and boolean-like strings: country: "NO", enabled: "yes"
  • Use a linter: yamllint catches indentation errors and type coercion risks before they reach production
  • Avoid tabs: YAML does not allow tab characters for indentation - use spaces only
  • Watch for the Norway problem: In YAML 1.1, NO, no, OFF, off, False, FALSE all parse as boolean false

The YAML 1.2 spec (2009) eliminated most of the implicit boolean conversions, but many tools still use YAML 1.1 parsers. Always check which YAML version your parser implements before relying on unquoted values.

Frequently Asked Questions

Can TOML replace YAML for Kubernetes configs?

Not directly. Kubernetes only accepts YAML or JSON for its manifests and API objects. TOML is not a supported input format in kubectl or the Kubernetes API. If you prefer TOML, you would need a build step that converts TOML to YAML before applying, which adds complexity with minimal benefit.

Is YAML a superset of JSON?

YAML 1.2 is technically a superset of JSON - any valid JSON document is also valid YAML 1.2. In practice, most YAML parsers have edge cases and version inconsistencies that make this superset relationship unreliable. Do not assume a YAML parser will correctly handle arbitrary JSON.

Why does pyproject.toml use TOML instead of YAML or JSON?

The Python packaging community chose TOML for pyproject.toml (PEP 518) specifically because of YAML's implicit type coercion risks and JSON's lack of comments. TOML's explicitness and support for comments make it well-suited for package metadata that is maintained by humans over long periods.

What is the best format for environment-specific config (dev/staging/prod)?

For configs that vary per environment, YAML with anchors is common (define a base config, override per environment). However, for maximum clarity and safety, environment-specific values are often better kept out of config files entirely and injected via environment variables - regardless of which format the base config uses.

Does TOML support inheritance or includes?

No. TOML has no built-in inheritance, includes, or anchors. If you need to share config across multiple TOML files, that logic must be handled by the application reading the files. This is a deliberate design choice - TOML prioritizes simplicity over power.

Use our free tool here → JSON ↔ YAML Converter to quickly convert between formats when migrating configs or comparing structures.

UK
Written by Usman Khan
DevOps Engineer | MSc Cybersecurity | CEH | AWS Solutions Architect

Usman has 10+ years of experience securing enterprise infrastructure, managing high-traffic servers, and building zero-knowledge security tools. Read more about the author.