Tom’s Obvious, Minimal Language.

By Tom Preston-Werner.

Latest tagged version:

NOTE: The master branch of this repository tracks the very latest development
and may contain features and changes that do not exist on any released version.
To find the spec for a specific version, look in the versions subdirectory.

As of version 0.5.0, TOML should be considered extremely stable. The goal is for
version 1.0.0 to be backwards compatible (as much as humanly possible) with
version 0.5.0. All implementations are strongly encouraged to become 0.5.0
compatible so that the transition to 1.0.0 will be simple when that happens.


TOML aims to be a minimal configuration file format that’s easy to read due to
obvious semantics. TOML is designed to map unambiguously to a hash table. TOML
should be easy to parse into data structures in a wide variety of languages.

Table of contents


# This is a TOML document.

title = "TOML Example"

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

server = ""
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true


  # Indentation (tabs and/or spaces) is allowed but not required
  ip = ""
  dc = "eqdc10"

  ip = ""
  dc = "eqdc10"

data = [ ["gamma", "delta"], [1, 2] ]

# Line breaks are OK when inside arrays
hosts = [


  • TOML is case sensitive.
  • A TOML file must be a valid UTF-8 encoded Unicode document.
  • Whitespace means tab (0x09) or space (0x20).
  • Newline means LF (0x0A) or CRLF (0x0D0A).


A hash symbol marks the rest of the line as a comment.

# This is a full-line comment
key = "value" # This is a comment at the end of a line

Key/Value Pair

The primary building block of a TOML document is the key/value pair.

Keys are on the left of the equals sign and values are on the right. Whitespace
is ignored around key names and values. The key, equals sign, and value must be
on the same line (though some values can be broken over multiple lines).

Values must be of the following types: String, Integer, Float, Boolean,
Datetime, Array, or Inline Table. Unspecified values are invalid.


A key may be either bare, quoted or dotted.

Bare keys may only contain ASCII letters, ASCII digits, underscores, and
dashes (A-Za-z0-9_-). Note that bare keys are allowed to be composed of only
ASCII digits, e.g. 1234, but are always interpreted as strings.

key = "value"
bare_key = "value"
bare-key = "value"
1234 = "value"

Quoted keys follow the exact same rules as either basic strings or literal
strings and allow you to use a much broader set of key names. Best practice is
to use bare keys except when absolutely necessary.

"" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"
'key2' = "value"
'quoted "value"' = "value"

A bare key must be non-empty, but an empty quoted key is allowed (though

= "no key name"  # INVALID
"" = "blank"     # VALID but discouraged
'' = 'blank'     # VALID but discouraged

Dotted keys are a sequence of bare or quoted keys joined with a dot. This
allows for grouping similar properties together:

name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true

In JSON land, that would give you the following structure:

  "name": "Orange",
  "physical": {
    "color": "orange",
    "shape": "round"
  "site": {
    "google.com": true

Whitespace around dot-separated parts is ignored, however, best practice is to
not use any extraneous whitespace.

Defining a key multiple times is invalid.

name = "Tom"
name = "Pradyun"

As long as a key hasn’t been directly defined, you may still write to it and
to names within it.

a.b.c = 1
a.d = 2
a.b = 1
a.b.c = 2


There are four ways to express strings: basic, multi-line basic, literal, and
multi-line literal. All strings must contain only valid UTF-8 characters.

Basic strings are surrounded by quotation marks. Any Unicode character may
be used except those that must be escaped: quotation mark, backslash, and the
control characters (U+0000 to U+001F, U+007F).

str = "I'm a string. "You can quote me". NametJosu00E9nLocationtSF."

For convenience, some popular characters have a compact escape sequence.

b         - backspace       (U+0008)
t         - tab             (U+0009)
n         - linefeed        (U+000A)
f         - form feed       (U+000C)
r         - carriage return (U+000D)
"         - quote           (U+0022)
\         - backslash       (U+005C)
uXXXX     - unicode         (U+XXXX)
UXXXXXXXX - unicode         (U+XXXXXXXX)

Any Unicode character may be escaped with the uXXXX or UXXXXXXXX forms.
The escape codes must be valid Unicode scalar values.

All other escape sequences not listed above are reserved and, if used, TOML
should produce an error.

Sometimes you need to express passages of text (e.g. translation files) or would
like to break up a very long string into multiple lines. TOML makes this easy.

Multi-line basic strings are surrounded by three quotation marks on each
side and allow newlines. A newline immediately following the opening delimiter
will be trimmed. All other whitespace and newline characters remain intact.

str1 = """
Roses are red
Violets are blue"""

TOML parsers should feel free to normalize newline to whatever makes sense for
their platform.

# On a Unix system, the above multi-line string will most likely be the same as:
str2 = "Roses are rednViolets are blue"

# On a Windows system, it will most likely be equivalent to:
str3 = "Roses are redrnViolets are blue"

For writing long strings without introducing extraneous whitespace, use a “line
ending backslash”. When the last non-whitespace character on a line is a , it
will be trimmed along with all whitespace (including newlines) up to the next
non-whitespace character or closing delimiter. All of the escape sequences that
are valid for basic strings are also valid for multi-line basic strings.

# The following strings are byte-for-byte equivalent:
str1 = "The quick brown fox jumps over the lazy dog."

str2 = """
The quick brown 

  fox jumps over 
    the lazy dog."""

str3 = """
       The quick brown 
       fox jumps over 
       the lazy dog.

Any Unicode character may be used except those that must be escaped: backslash
and the control characters (U+0000 to U+001F, U+007F). Quotation marks need not
be escaped unless their presence would create a premature closing delimiter.

If you’re a frequent specifier of Windows paths or regular expressions, then
having to escape backslashes quickly becomes tedious and error prone. To help,
TOML supports literal strings which do not allow escaping at all.

Literal strings are surrounded by single quotes. Like basic strings, they
must appear on a single line:

# What you see is what you get.
winpath  = 'C:Usersnodejstemplates'
winpath2 = '\ServerXadmin$system32'
quoted   = 'Tom "Dubs" Preston-Werner'
regex    = ''

Since there is no escaping, there is no way to write a single quote inside a
literal string enclosed by single quotes. Luckily, TOML supports a multi-line
version of literal strings that solves this problem.

Multi-line literal strings are surrounded by three single quotes on each
side and allow newlines. Like literal strings, there is no escaping whatsoever.
A newline immediately following the opening delimiter will be trimmed. All
other content between the delimiters is interpreted as-is without modification.

regex2 = '''I [dw]on't need d{2} apples'''
lines  = '''
The first newline is
trimmed in raw strings.
   All other whitespace
   is preserved.

Control characters other than tab are not permitted in a literal string. Thus,
for binary data it is recommended that you use Base64 or another suitable ASCII
or UTF-8 encoding. The handling of that encoding will be application specific.


Integers are whole numbers. Positive numbers may be prefixed with a plus sign.
Negative numbers are prefixed with a minus sign.

int1 = +99
int2 = 42
int3 = 0
int4 = -17

For large numbers, you may use underscores between digits to enhance
readability. Each underscore must be surrounded by at least one digit on each

int5 = 1_000
int6 = 5_349_221
int7 = 1_2_3_4_5     # VALID but discouraged

Leading zeros are not allowed. Integer values -0 and +0 are valid and
identical to an unprefixed zero.

Non-negative integer values may also be expressed in hexadecimal, octal, or
binary. In these formats, leading zeros are allowed (after the prefix). Hex
values are case insensitive. Underscores are allowed between digits (but not
between the prefix and the value).

# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef

# octal with prefix `0o`
oct1 = 0o01234567
oct2 = 0o755 # useful for Unix file permissions

# binary with prefix `0b`
bin1 = 0b11010110

64 bit (signed long) range expected (−9,223,372,036,854,775,808 to


Floats should be implemented as IEEE 754 binary64 values.

A float consists of an integer part (which follows the same rules as integer
values) followed by a fractional part and/or an exponent part. If both a
fractional part and exponent part are present, the fractional part must precede
the exponent part.

# fractional
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01

# exponent
flt4 = 5e+22
flt5 = 1e6
flt6 = -2E-2

# both
flt7 = 6.626e-34

A fractional part is a decimal point followed by one or more digits.

An exponent part is an E (upper or lower case) followed by an integer part
(which follows the same rules as integer values).

Similar to integers, you may use underscores to enhance readability. Each
underscore must be surrounded by at least one digit.

flt8 = 9_224_617.445_991_228_313

Float values -0.0 and +0.0 are valid and should map according to IEEE 754.

Special float values can also be expressed. They are always lowercase.

# infinity
sf1 = inf  # positive infinity
sf2 = +inf # positive infinity
sf3 = -inf # negative infinity

# not a number
sf4 = nan  # actual sNaN/qNaN encoding is implementation specific
sf5 = +nan # same as `nan`
sf6 = -nan # valid, actual encoding is implementation specific


Booleans are just the tokens you’re used to. Always lowercase.

bool1 = true
bool2 = false

Offset Date-Time

To unambiguously represent a specific instant in time, you may use an
RFC 3339 formatted date-time with offset.

odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00

For the sake of readability, you may replace the T delimiter between date and
time with a space (as permitted by RFC 3339 section 5.6).

odt4 = 1979-05-27 07:32:00Z

The precision of fractional seconds is implementation specific, but at least
millisecond precision is expected. If the value contains greater precision than
the implementation can support, the additional precision must be truncated, not

Local Date-Time

If you omit the offset from an RFC 3339
formatted date-time, it will represent the given date-time without any relation
to an offset or timezone. It cannot be converted to an instant in time without
additional information. Conversion to an instant, if required, is implementation

ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999

The precision of fractional seconds is implementation specific, but at least
millisecond precision is expected. If the value contains greater precision than
the implementation can support, the additional precision must be truncated, not

Local Date

If you include only the date portion of an
RFC 3339 formatted date-time, it will
represent that entire day without any relation to an offset or timezone.

Local Time

If you include only the time portion of an RFC
formatted date-time, it will represent
that time of day without any relation to a specific day or any offset or

lt1 = 07:32:00
lt2 = 00:32:00.999999

The precision of fractional seconds is implementation specific, but at least
millisecond precision is expected. If the value contains greater precision than
the implementation can support, the additional precision must be truncated, not


Arrays are square brackets with values inside. Whitespace is ignored. Elements
are separated by commas. Data types may not be mixed (different ways to define
strings should be considered the same type, and so should arrays with different
element types).

arr1 = [ 1, 2, 3 ]
arr2 = [ "red", "yellow", "green" ]
arr3 = [ [ 1, 2 ], [3, 4, 5] ]
arr4 = [ "all", 'strings', """are the same""", '''type''']
arr5 = [ [ 1, 2 ], ["a", "b", "c"] ]

arr6 = [ 1, 2.0 ] # INVALID

Arrays can also be multiline. Terminating commas (also called trailing commas)
are ok after the last value of the array. There can be an arbitrary number of
newlines and comments before a value and before the closing bracket.

arr7 = [
  1, 2, 3

arr8 = [
  2, # this is ok


Tables (also known as hash tables or dictionaries) are collections of key/value
pairs. They appear in square brackets on a line by themselves. You can tell them
apart from arrays because arrays are only ever values.

Under that, and until the next table or EOF are the key/values of that table.
Key/value pairs within tables are not guaranteed to be in any specific order.

key1 = "some string"
key2 = 123

key1 = "another string"
key2 = 456

Naming rules for tables are the same as for keys (see definition of Keys above).

type.name = "pug"

In JSON land, that would give you the following structure:

{ "dog": { "tater.man": { "type": { "name": "pug" } } } }

Whitespace around the key is ignored, however, best practice is to not use any
extraneous whitespace.

[a.b.c]            # this is best practice
[ d.e.f ]          # same as [d.e.f]
[ g .  h  . i ]    # same as [g.h.i]
[ j . "ʞ" . 'l' ]  # same as [j."ʞ".'l']

You don’t need to specify all the super-tables if you don’t want to. TOML knows
how to do it for you.

# [x] you
# [x.y] don't
# [x.y.z] need these
[x.y.z.w] # for this to work

Empty tables are allowed and simply have no key/value pairs within them.

Like keys, you cannot define any table more than once. Doing so is invalid.


b = 1

c = 2

b = 1

c = 2

Inline Table

Inline tables provide a more compact syntax for expressing tables. They are
especially useful for grouped data that can otherwise quickly become verbose.
Inline tables are enclosed in curly braces { and }. Within the braces, zero
or more comma separated key/value pairs may appear. Key/value pairs take the
same form as key/value pairs in standard tables. All value types are allowed,
including inline tables.

Inline tables are intended to appear on a single line. No newlines are allowed
between the curly braces unless they are valid within a value. Even so, it is
strongly discouraged to break an inline table onto multiples lines. If you find
yourself gripped with this desire, it means you should be using standard tables.

name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
animal = { type.name = "pug" }

The inline tables above are identical to the following standard table

first = "Tom"
last = "Preston-Werner"

x = 1
y = 2

type.name = "pug"

Array of Tables

The last type that has not yet been expressed is an array of tables. These can
be expressed by using a table name in double brackets. Each table with the same
double bracketed name will be an element in the array. The tables are inserted
in the order encountered. A double bracketed table without any key/value pairs
will be considered an empty table.

name = "Hammer"
sku = 738594937


name = "Nail"
sku = 284758393
color = "gray"

In JSON land, that would give you the following structure.

  "products": [
    { "name": "Hammer", "sku": 738594937 },
    { },
    { "name": "Nail", "sku": 284758393, "color": "gray" }

You can create nested arrays of tables as well. Just use the same double bracket
syntax on sub-tables. Each double-bracketed sub-table will belong to the most
recently defined table element above it.

  name = "apple"

    color = "red"
    shape = "round"

    name = "red delicious"

    name = "granny smith"

  name = "banana"

    name = "plantain"

The above TOML maps to the following JSON.

  "fruit": [
      "name": "apple",
      "physical": {
        "color": "red",
        "shape": "round"
      "variety": [
        { "name": "red delicious" },
        { "name": "granny smith" }
      "name": "banana",
      "variety": [
        { "name": "plantain" }

Attempting to append to a statically defined array, even if that array is empty
or of compatible type, must produce an error at parse time.

fruit = []

[[fruit]] # Not allowed

Attempting to define a normal table with the same name as an already established
array must produce an error at parse time.

  name = "apple"

    name = "red delicious"

  # This table conflicts with the previous table
    name = "granny smith"

You may also use inline tables where appropriate:

points = [ { x = 1, y = 2, z = 3 },
           { x = 7, y = 8, z = 9 },
           { x = 2, y = 4, z = 8 } ]

Filename Extension

TOML files should use the extension .toml.


When transferring TOML files over the internet, the appropriate MIME type is

Comparison with Other Formats

In some ways TOML is very similar to JSON: simple, well-specified, and
maps easily to ubiquitous data types. JSON is great for serializing
data that will mostly be read and written by computer programs. Where
TOML differs from JSON is its emphasis on being easy for humans to
read and write. Comments are a good example: they serve no purpose
when data is being sent from one program to another, but are very
helpful in a configuration file that may be edited by hand.

The YAML format is oriented towards configuration files just like
TOML. For many purposes, however, YAML is an overly complex
solution. TOML aims for simplicity, a goal which is not apparent in
the YAML specification: http://www.yaml.org/spec/1.2/spec.html

The INI format is also frequently used for configuration files. The
format is not standardized, however, and usually does not handle more
than one or two levels of nesting.

Get Involved

Documentation, bug reports, pull requests, and all other contributions
are welcome!


We have an Official TOML Wiki that
catalogs the following:

  • Projects using TOML
  • Implementations
  • Validators
  • Language agnostic test suite for TOML decoders and encoders
  • Editor support
  • Encoders
  • Converters

Please take a look if you’d like to view or add to that list. Thanks for being
a part of the TOML community!

  1. Waldenbuch Ferienwohnung

    Beautiful quiet 1-room apartment / kitchen / bath / WC / SAT-TV / Internet / washing machine In the countryside, comfortable, at the end of a cul-de-sac, bright quiet 1-room apartment with separate, private entrance. The apartment was completely renovated in May 2018 and refurbished. Parking is available on the public road and are always available. The apartment has a 40 inch satellite TV, a washing machine, as well as internet (wi-fi) for a small fee. An iron and ironing board are also available. In the kitchen you will find an oven with ceramic hob, a dishwasher, a refrigerator with 4-star freezer, a coffee machine, kettle and a toaster. The chocolate “shop” factory outlet of the world-famous brand Ritter Sport as well as the Ritter Museum and the Ritter Museums-Café can be reached after about 450 meters or 6 minutes on foot. For nature lovers, the beautiful Schönbuch forest invites you right outside the front door to walks or hikes. Waldenbuch is located on the northern edge of the forest and the natural park Schönbuch about 17 km south of Stuttgart and has about 8500 inhabitants. It is about 14 km to Böblingen, 19 km to Tübingen and about 12 km to the Messe Stuttgart. Idyllically located in the valley, Waldenbuch today radiates a special charm with its half-timbered houses, fountains and seasons in the historic old town center. Both the town church of St. Veit with its 36 meter high church tower and the beautiful castle delight the guests. 24h check-in by arrangement possible Food discounters such as Lidl, DM drugstore market, penny market and beverage market can be reached on foot in about 5 to 20 minutes. Due to the quiet but central location of the apartment is by car in a short time in Stuttgart, Tübingen, Esslingen, Böblingen the outlet city Metzingen or Sindelfingen.

  2. Ferienwohnung Filderstadt

    TOP !!! Schöne ruhige 1-Zimmer Wohnung / Küche / BAD / WC / SAT-TV / Internet / Waschmaschine Im Grünen gelegene, komfortable, am Ende einer Sackgasse, helle ruhige 1-Zimmerwohnung mit separatem, eigenem Eingang. TOP !!!Die Wohnung wurde im Mai 2018 komplett renoviert und Neu eingerichtet. TOP !!! Parkplatzmöglichkeiten gibt es auf der öffentlichen Straße und sind in der Regel immer vorhanden. TOP !!! Die Wohnung hat einen 40 Zoll Sat-TV, eine Waschmaschine, sowie Internet (Wlan) gegen eine kleine Gebühr. Ein Bügeleisen und Bügelbrett sind ebenfalls forhanden. In der Küche finden Sie neben einem Backofen mit Cerankochfeld, eine Geschirspülmaschine, einen Kühlschrank mit 4-Sterne Gefrierfach, eine Kaffeemaschine ,Wasserkocher sowie einen Toaster. Der Schoko- “laden“ Werksverkauf der Weltberühmten Marke Ritter Sport sowie das Ritter Museum und das Ritter Museums-Café erreichen sie nach ca. 450 Meter bzw. 6 Minuten zu Fuß. Für Naturliebhaber lädt der schöne Schönbuch-Wald direkt vor der Haustüre zu Spaziergängen oder Wanderungen ein. Waldenbuch liegt am Nördlichen Rand des Waldgebiets und gleichnamigen Naturparks Schönbuch ca. 17 km südlich von Stuttgart und hat ca. 8500 Einwohner. Nach Böblingen sind es ca.14 km, nach Tübingen ca. 19 km und zur Messe Stuttgart ca. 12 km. Idyllisch im Tal gelegen strahlt Waldenbuch heute mit seinen Fachwerkhäusern, Brunnen und Staffeln im historischen Altstadtkern einen ganz besonderen Charme aus. Sowohl die Stadtkirche St. Veit mit ihrem 36 Meter hohen Kirchturm als auch das wunderschöne Schloss begeistern die Gäste. 24h Check-In nach Absprache möglich Lebensmitteldiscounter wie Lidl, DM-Drogerie-Markt, Penny Markt und Getränkemarkt erreicht man zu Fuß in ca. 5 bis 20 Minuten. Durch die ruhige aber dennoch zentrale Lage der Wohnung ist man mit dem Auto in kurzer Zeit in Stuttgart, Tübingen, Esslingen, Böblingen der Outlet-Stadt Metzingen oder Sindelfingen.

  3. Aurelio Naughton

    Fantastic site you have here but I was curious if you knew of any discussion boards that cover the same topics talked about in this article? I’d really love to be a part of online community where I can get comments from other experienced individuals that share the same interest. If you have any recommendations, please let me know. Many thanks!

  4. Jurassic Dildo

    Thank you for publishing this awesome article. I’m a long time reader but I’ve never been compelled to leave a comment. I subscribed to your blog and shared this on my Facebook. Thanks again for a great article!

  5. Kit Dion

    I’ve noticed that credit score improvement activity has to be conducted with techniques. If not, you may find yourself endangering your standing. In order to be successful in fixing your credit score you have to confirm that from this moment you pay any monthly fees promptly prior to their timetabled date. Really it is significant because by certainly not accomplishing that area, all other steps that you will choose to use to improve your credit positioning will not be efficient. Thanks for giving your strategies.

  6. Automated Trading

    I like the helpful info you provide for your articles. I will bookmark your blog and take a look at again right here frequently. I’m relatively sure I will be told a lot of new stuff proper right here! Good luck for the following!

Leave a Reply

Your email address will not be published. Required fields are marked *