Skip to content

What is wrong with TOML?

# This is a TOML document.

title = "TOML Example"

name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00 # First class dates

TOML is a configuration designed as a sort of "improved" INI file. It's analogous to this project - StrictYAML, a similar attempt to fix YAML's flaws:

# All about the character
name: Ford Prefect
age: 42
- Towel

I'm not going to argue here that TOML is the worst file format out there - if you use it infrequently on small and simple files it does its job fine.

It's a warning though: as you scale up its usage, many bad warts start to appear.

Martin Vejnár, the author of PyTOML argued exactly this. He initially built a TOML parser out of enthusiasm for this new format but later abandoned it. When asked if he would like to see his library used as a dependency for pip as part of PEP-518, he said no - and explained why he abandoned the project:

TOML is a bad file format. It looks good at first glance, and for really really trivial things it is probably good. But once I started using it and the configuration schema became more complex, I found the syntax ugly and hard to read.

Despite this, PyPA still went ahead and used TOML for PEP-518. Fortunately pyproject.toml is fairly trivial and appears just once per project so the problems he alludes to aren't that pronounced.

StrictYAML, by contrast, was designed to be a language to write readable 'story' tests where there will be many files per project with more complex hierarchies, a use case where TOML starts to really suck.

So what specifically is wrong with TOML when you scale it up?

1. It's very verbose. It's not DRY. It's syntactically noisy.

In this example of a StrictYAML story and its equivalent serialized TOML the latter ends up spending 50% more characters to represent the exact same data.

This is largely due to the design decision to have the full name of every key being associated with every value which is not DRY.

It is also partly due to the large numbers of syntactic cruft - quotation marks and square brackets dominate TOML documents whereas in the StrictYAML example they are absent.

Shortening program lengths (and DRYing code), all other things being equal, reduces the number of bugs significantly because maintenance becomes easier and deriving intent from the code becomes clearer. What goes for Turing-complete code also applies to configuration code.

2. TOML's hierarchies are difficult to infer from syntax alone

Mapping hierarchy in TOML is determined by dots. This is simple enough for parsers to read and understand but this alone makes it difficult to perceive the relationships between data.

This has been recognized by many TOML writers who have adopted a method that will be quite familiar to a lot of programmers - indentation that the parser ignores:

Non-meaningful indentation

This parallels the way indentation is added in lots of programming languages that have syntactic markers like brackets - e.g. JSON, Javascript or Java are all commonly rendered with non-parsed indentation to make it easier for humans to understand them.

But not Python.

Python, has long been a stand out exception in how it was designed - syntactic markers are not necessary to infer program structure because indentation is the marker that determines program structure.

This argument over the merits of meaningful indentation in Python has been going on for decades, and not everybody agrees with this, but it's generally considered a good idea - usually for the reasons argued in this stack exchange question:

  1. Python inherited the significant indentation from the (now obsolete) predecessor language ABC. ABC is one of the very few programming languages which have used usability testing to direct the design. So while discussions about syntax usually comes down to subjective opinions and personal preferences, the choice of significant indentation actually has a sounder foundation.

  2. Guido van Rossum came across subtle bugs where the indentation disagreed with the syntactic grouping. Meaningful indentation fixed this class of bug. Since there are no begin/end brackets there cannot be a disagreement between grouping perceived by the parser and the human reader.

  3. Having symbols delimiting blocks and indentation violates the DRY principle.

  4. It does away with the typical religious C debate of "where to put the curly braces" (although TOML is not yet popular enough to inspire such religious wars over indentation... yet).

3. Overcomplication: Like YAML, TOML has too many features

Somewhat ironically, TOML's creator quite rightly criticizes YAML for not aiming for simplicity and then falls into the same trap itself - albeit not quite as deeply.

One way it does this is by trying to include date and time parsing which imports all of the inherent complications associated with dates and times.

Dates and times, as many more experienced programmers are probably aware is an unexpectedly deep rabbit hole of complications and quirky, unexpected, headache and bug inducing edge cases. TOML experiences many of these edge cases because of this.

The best way to deal with essential complexity like these is to decouple, isolate the complexity and delegate it to a specialist tool that is good at handling that specific problem which you can swap out later if required.

This the approach that JSON took (arguably a good decision) and it's the approach that StrictYAML takes too.

StrictYAML the library (as opposed to the format) has a validator that uses Python's most popular date/time parsing library although developers are not obliged or even necessarily encouraged to use this. StrictYAML parses everything as a string by default and whatever validation occurs later is considered to be outside of its purview.

4. Syntax typing

Like most other markup languages TOML has syntax typing - the writer of the markup decides if, for example, something should be parsed as a number or a string:

flt2 = 3.1415
string = "hello"

Programmers will feel at home maintaining this, but non programmers tend to find the difference between "1.5" and 1.5 needlessly confusing.

StrictYAML does not require quotes around any value to infer a data type because the schema is assumed to be the single source of truth for type information:

flt2: 3.1415
string: hello

In the above example it just removes two characters, but in larger documents with more complex data, pushing type parsing decision to the schema (or assuming strings) removes an enormous amount of syntactic noise.

The lack of syntax typing combined with the use of indentation instead of square brackets to denote hierarchies makes equivalent StrictYAML documents 10-20% shorter, cleaner and ultimately more readable.

Advantages of TOML still has over StrictYAML

There are currently still a few:

  • StrictYAML does not currently have an "official spec". The spec is currently just "YAML 1.2 with features removed". This has some advantages (e.g. YAML syntax highlighting in editors works just fine) but also some disadvantages (some documents will render differently).
  • StrictYAML does not yet have parsers in languages other than Python. If you'd like to write one for your language (if you don't also do validation it actually wouldn't be very complicated), contact me, I'd love to help you in any way I can - including doing a test suite and documentation.
  • Popularity.