Skip to content
T
Tools.Town
Free Online Tools for Everyone
Data Tools

TOML to JSON: A Complete Guide to the Format and How to Convert It

Everything you need to know about TOML — its syntax, design philosophy, type system, and how to convert TOML to JSON reliably in Python, Go, and JavaScript.

25 June 2026 4 min read By Tools.Town Team Fact Checked

Key Takeaways

  • TOML stands for Tom's Obvious Minimal Language, named after its creator Tom Preston-Werner, co-founder of GitHub
  • TOML and YAML serve similar purposes but TOML's explicit type system and unambiguous parsing rules make it far less error-prone
  • Yes — TOML supports single-line comments using the # character, which is one of its key advantages over JSON for configuration files
  • A standard table [section] defines a single mapping

What is TOML?

TOML stands for Tom’s Obvious Minimal Language. Tom Preston-Werner, the co-founder of GitHub, created it in 2013 out of frustration with existing configuration file formats. His stated goal was a format that would be “obvious” — something a human could read and write without needing to memorise arcane rules, something that maps unambiguously to a hash table, and something that a machine could parse without guesswork.

The name is intentionally self-referential and slightly tongue-in-cheek, but the goals behind it are serious. By 2013, the two dominant choices for configuration files were JSON and YAML. JSON was originally designed for data interchange between programs, not for humans to maintain by hand — it lacks comments, requires double-quotes around every key, and has no native date type. YAML solved some of those problems but introduced new ones: indentation-sensitive parsing, implicit type coercion, and a specification so complex that almost no two YAML parsers agreed on edge cases. TOML was designed to sit in between — simpler than YAML, more human-friendly than JSON.

The TOML to JSON converter on Tools.Town lets you instantly translate TOML documents into JSON, which is useful when you need to inspect a Cargo.toml file, feed configuration data to a JSON-only API, or simply understand what your TOML actually means as a data structure.

The design philosophy behind TOML

TOML has three core design principles that distinguish it from competing formats. First, it should be obviously readable by humans. Key-value pairs look like assignment statements, section headings look like IRC channel names in square brackets, and the overall structure resembles a traditional INI file that most developers already find intuitive. Second, it should map unambiguously to a hash table. Unlike YAML, where the same document can be interpreted differently by different parsers, a valid TOML file produces exactly one possible data structure. Third, it should be easy to parse. The grammar is small enough to be implemented correctly in a few hundred lines of code in most languages, and the TOML specification is precise enough that parsers tend to agree.

These principles have consequences. TOML is explicit about types — a string is always in quotes, a date always follows RFC 3339, an integer never looks like a float. There is no implicit coercion. The value NO is not a boolean false (that would be TOML’s false in lowercase). The value 1.0 is not an integer. Every value wears its type on its sleeve.

Key-value pairs: the basic building block

Every TOML document is a collection of key-value pairs. A bare key can contain ASCII letters, digits, dashes, and underscores. A quoted key uses double quotes and can contain any Unicode character, which is useful for keys that contain spaces or special characters.

name = "Ferris"
port = 8080
debug = false

Dotted keys allow you to write nested tables inline. The key server.host is equivalent to writing a [server] table containing a host key.

server.host = "localhost"
server.port = 3000

Defining the same key twice at the same level is an error in TOML. This rigidity is intentional — it prevents the category of bug where a configuration file silently overrides an earlier value.

String types

TOML has four string types, each solving a different authoring need. Basic strings use double quotes and support escape sequences: \n for newline, \t for tab, \\ for a literal backslash, \" for a literal double-quote, and \uXXXX or \UXXXXXXXX for Unicode code points.

message = "Hello, World!\nSecond line."
path = "C:\\Users\\Ferris\\documents"

Literal strings use single quotes and contain no escape sequences at all — whatever is between the single quotes is the exact string value. This is perfect for regular expressions and Windows paths, where backslashes should not be interpreted.

pattern = '\d{3}-\d{4}'

Multi-line basic strings use three double-quotes on each side and support the same escape sequences as basic strings. A newline immediately after the opening delimiter is trimmed, which makes formatting cleaner.

description = """
This is a long description
that spans multiple lines.
"""

Multi-line literal strings use three single-quotes and similarly suppress escape processing throughout the entire block.

Integer types

TOML integers can be written in four bases. Decimal is the default. Hexadecimal values are prefixed with 0x, octal with 0o, and binary with 0b.

decimal = 42
hex     = 0xDEADBEEF
octal   = 0o755
binary  = 0b11010110

TOML also permits underscore separators within integer literals for readability, similar to Python and Rust. The underscores have no semantic meaning and are stripped by parsers.

one_million = 1_000_000
byte_mask   = 0b1111_0000

Float types

Floats follow IEEE 754 double precision. They must always contain a decimal point or an exponent to be distinguished from integers. TOML supports scientific notation, positive and negative infinity (inf, +inf, -inf), and the not-a-number value (nan).

pi          = 3.14159
avogadro    = 6.022e23
small       = 1.5e-10
positive_inf = inf
not_a_number = nan

The explicit distinction between integers and floats is one area where TOML is stricter than JSON, which treats all numbers uniformly and leaves it to applications to decide how to interpret them.

Booleans and datetimes

TOML booleans are true and false — always lowercase, never quoted. The format also has native support for four date and time types based on RFC 3339: offset datetime (with timezone), local datetime (no timezone), local date, and local time. This is one of the features that truly sets TOML apart from both JSON (which has no date type) and YAML (which has date support but with notorious implicit coercion problems).

enabled    = true
created_at = 2024-01-15T09:30:00Z
meeting    = 2024-03-21T14:00:00+05:30
date_only  = 2024-06-25
time_only  = 14:30:00

Arrays

TOML arrays are written with square brackets and can contain any mix of value types — though in practice, homogeneous arrays are more common and idiomatic. Arrays can span multiple lines, and trailing commas are allowed.

ports       = [8080, 8081, 8082]
names       = ["Alice", "Bob", "Charlie"]
mixed       = [1, "two", 3.0]
multi_line  = [
  "first",
  "second",
  "third",
]

Inline tables

Inline tables are a compact way to express a table on a single line. They are enclosed in curly braces and are useful when a nested value is small enough that a full section header would feel excessive.

point = { x = 1, y = 2 }
author = { name = "Tom", email = "tom@example.com" }

Inline tables cannot contain newlines, and you cannot add keys to an inline table after it has been defined. They are intentionally limited to encourage using standard tables for anything complex.

Standard tables and arrays of tables

A standard table is declared with a name in square brackets. All key-value pairs following the header belong to that table until the next header or the end of the file.

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

[server]
host = "0.0.0.0"
port = 8080

Arrays of tables use double square brackets. Each occurrence of [[section]] creates a new element and appends it to an array under that key.

[[products]]
name  = "Hammer"
price = 9.99

[[products]]
name  = "Wrench"
price = 14.99

This is equivalent to the JSON structure { "products": [{"name": "Hammer", "price": 9.99}, {"name": "Wrench", "price": 14.99}] }. You can verify exactly what your TOML produces by pasting it into the TOML to JSON converter.

TOML vs YAML: why explicitness matters

The most common comparison for TOML is with YAML, because both target human-maintained configuration files. The fundamental difference is that TOML is schema-aware and explicit, while YAML relies on indentation and implicit type inference.

YAML’s implicit typing has been responsible for a long list of production bugs. The classic example is the “Norway problem”: in YAML 1.1, the bare value NO is parsed as boolean false, which means a configuration entry for the country code NO could silently become false. YAML also allows tabs for indentation in some contexts but not others, creating parsing surprises. The YAML specification runs to dozens of pages and covers features that virtually no real-world configuration file ever needs.

TOML avoids all of this by requiring every value to declare its type through its syntax. If you want a string, you quote it. If you want a boolean, you write true or false exactly as written here. There is no inference, no surprise coercion, no ambiguity. The specification is small enough to read in an afternoon, and parsers in every language implement it consistently. For more on working with JSON after conversion, the JSON Formatter guide explains how to validate and pretty-print the output.

Why Rust’s Cargo.toml popularised the format

TOML might have remained a niche curiosity if not for the Rust programming language. When the Rust team designed Cargo — Rust’s package manager and build system — in 2014, they chose TOML as the format for Cargo.toml manifest files. This single decision exposed TOML to every Rust developer in the world.

A typical Cargo.toml demonstrates TOML’s strengths clearly. It has a [package] table for metadata, a [dependencies] table for library dependencies, optional [[bin]] and [[example]] arrays-of-tables, and feature flags in [features]. The format is clean, easy to edit by hand, and generates no surprises. As Rust grew in popularity through the late 2010s and into the 2020s, TOML grew with it.

Other tools followed. The Python packaging system adopted TOML for pyproject.toml. Various static site generators, game engines, and developer tools now use TOML as their default configuration format.

Using TOML in Python

Python 3.11 added tomllib to the standard library — the first time Python shipped with built-in TOML support. For Python 3.10 and earlier, the third-party tomli library provides an identical API.

import tomllib  # Python 3.11+
# import tomli as tomllib  # Python 3.10 and earlier

with open("config.toml", "rb") as f:
    config = tomllib.load(f)

print(config["database"]["host"])

Note that tomllib opens files in binary mode ("rb"), not text mode. The library handles UTF-8 decoding internally. The returned value is a plain Python dictionary, so you access nested values with normal dictionary indexing. If you need to write TOML from Python, the tomli-w package provides a complementary tomli_w.dumps() function.

Using TOML in Go

The github.com/BurntSushi/toml package is the de facto standard TOML library for Go. It uses struct tags in the same style as encoding/json to map TOML keys to Go struct fields.

import "github.com/BurntSushi/toml"

type Config struct {
    Database struct {
        Host string `toml:"host"`
        Port int    `toml:"port"`
    } `toml:"database"`
}

var cfg Config
if _, err := toml.DecodeFile("config.toml", &cfg); err != nil {
    log.Fatal(err)
}

The library handles all TOML types including datetimes, which map to time.Time in Go.

Using TOML in JavaScript

JavaScript does not include a built-in TOML parser, but the @iarna/toml and smol-toml packages are popular choices for Node.js and browser environments. Since browser-based tools cannot import npm packages directly, the TOML to JSON converter on Tools.Town uses a hand-rolled parser that handles the full TOML v1.0 specification without any dependencies — useful when you want to inspect a TOML document without setting up a local environment.

import { parse } from 'smol-toml';
const config = parse(tomlString);
console.log(config.database.host);

TOML’s combination of human-friendliness, explicit typing, and clean mapping to data structures makes it an excellent choice for any application configuration file. Once you understand the syntax covered in this guide, you can read and write Cargo.toml, pyproject.toml, and any other TOML file with confidence.

Advertisement

Try TOML to JSON — Free

Apply what you just learned with our free tool. No sign-up required.

Try TOML to JSON

Frequently Asked Questions

What does TOML stand for?
TOML stands for Tom's Obvious Minimal Language, named after its creator Tom Preston-Werner, co-founder of GitHub.
Is TOML better than YAML?
TOML and YAML serve similar purposes but TOML's explicit type system and unambiguous parsing rules make it far less error-prone. YAML's implicit type coercion has caused numerous production bugs, while TOML's strictness prevents them.
Can TOML have comments?
Yes — TOML supports single-line comments using the # character, which is one of its key advantages over JSON for configuration files.
What is the difference between a TOML table and an array of tables?
A standard table [section] defines a single mapping. An array of tables [[section]] defines a sequence of mappings — each [[section]] block creates a new element appended to the array.
Why does Rust use TOML for Cargo.toml?
The Rust community chose TOML for Cargo because it is human-readable, supports comments, has an unambiguous type system, and maps cleanly to the data structures Cargo needs without the footguns present in YAML.

Was this guide helpful?

Your feedback helps us improve our content.

Continue Reading

All Data Tools Guides

Get the best Data Tools tips & guides in your inbox

Join 25,000+ users who get our weekly data tools insights.