In the world of configuration files, TOML (Tom’s Obvious Minimal Language) has emerged as a popular format for its simplicity, readability, and human-friendly syntax. TOML is widely used in modern programming ecosystems, including Rust and Python, where readability and maintainability are critical. In this blog, we’ll dive deep into TOML keys, understanding their syntax, usage, and nuances, with examples to make it crystal clear.
What Are TOML Keys?
In TOML, keys are used to identify values in a key-value pair. They are essential building blocks of TOML configuration files, much like variables in programming. Keys in TOML can be unquoted strings, quoted strings, or dotted paths.
Syntax of a Key-Value Pair
A basic key-value pair in TOML looks like this:
key = "value"
Here,
key
is the name (identifier).value
is the corresponding value assigned to that key.
Types of Keys in TOML
There are three types of keys: bare, quoted, and dotted.
Bare keys
When you’re using bare keys (keys without quotes) in a file like TOML (a configuration file format), there are specific rules for naming them:
1. You can only use:
- English letters (A-Z, a-z)
- Numbers (0–9)
- Underscores (_)
- Dashes (-)
2. Bare keys can be made up of just numbers (like 1234
), but even in that case, they will be treated as text (a string), not a number.
3. A bare key (a key without quotes) must not be empty — it has to contain at least one letter, number, underscore, or dash.
# valid bare keys
key = "value"
bare_key = "value" # Valid, uses letters and underscore
bare-key = "value" # Valid, uses letters and a dash
1234 = "value" # Valid, but 1234 is treated as a string
# invalid bare keys
= "value" # as we see here no key name is used, so bare key can't be empty
Quoted keys
Quoted keys are keys that are enclosed in quotes (either single '
or double "
quotes). They can follow the same rules as basic strings or literal strings. This means you can use a wider variety of characters for the key name, like spaces or special symbols, which are not allowed in bare keys.
"key with space" = "value" # Valid, space allowed in quoted key
"key@#%" = "value" # Valid, special characters allowed
Best practice: It’s usually better to use bare keys (without quotes) because they are simpler and more common. Use quoted keys only when you really need them, like when your key has special characters that bare keys can’t handle.
Also, as we know, bare key must not be empty, However, we can have an empty quoted key (a key with quotes), but it’s not recommended to do so.
For example, this is valid but not ideal:
"" = "value" # Empty quoted key is allowed but discouraged
'' = 'blank' # again VALID but discouraged
So, while empty quoted keys are allowed, it’s better to avoid them if possible!
Note: Bare keys and quoted keys essentially mean the same thing—they’re just two different ways to represent the same key. However, we can’t use both in the same place. It needs to be either one or the other, but not both. For example, this won’t work:
# THIS WILL NOT WORK
spelling = "favorite"
"spelling" = "favourite"
Dotted keys
Dotted keys allow you to organize properties into groups by separating them with a dot (.
). You can use either bare or quoted keys, and it helps structure related data, like categories or sub-properties.
name = "Orange" # A single key
physical.color = "orange" # Grouped under 'physical'
physical.shape = "round" # Another property under 'physical'
site."softaai.com" = true # A key with a dot in it (quoted)
For better understanding, this is how it would look in JSON:
{
"name": "Orange",
"physical": {
"color": "orange",
"shape": "round"
},
"site": {
"softaai.com": true
}
}
Whitespace rules:
- Whitespace around the dots is ignored. However, it’s better to avoid extra spaces for clarity.
- Indentation (spaces at the beginning of a line) doesn’t matter and is ignored.
- These are all treated the same:
fruit.name = "banana" # Best practice
fruit. color = "yellow" # Same as fruit.color (extra space)
fruit . flavor = "banana" # Same as fruit.flavor (extra space)
Ordering rule:
While it’s technically valid to define dotted keys out-of-order, it’s discouraged because it can make your code harder to read and understand. When you define the properties of related items (like apple
and orange
), it’s better to keep them grouped together.
Valid but discouraged:
apple.type = "fruit"
orange.type = "fruit"
apple.skin = "thin"
orange.skin = "thick"
apple.color = "red"
orange.color = "orange"
Recommended (better approach):
apple.type = "fruit"
apple.skin = "thin"
apple.color = "red"
orange.type = "fruit"
orange.skin = "thick"
orange.color = "orange"
Dotted key & Table Rule:
Before going into the rules, understanding the table in TOML is important. We will look at the table in detail in the respective section, but for now, just understand the basics so that it will help in grasping the dotted key rules.
Tables are used to group related key-value pairs. There are two types of tables based on their usage: regular tables and nested tables.
- Nested Tables: These tables use dot notation to organize hierarchical data.
- Inline Tables: Mentioned briefly, inline tables are used for small data sets with a simpler syntax.
# Regular Table server
[server]
host = "127.0.0.1"
port = 8080
# Nested Table
[server.logging]
level = "debug"
output = "stdout"
# Inline Table
user = { name = "amol", age = 28 }
Rule 1
In TOML, if a key hasn’t been defined yet, you can still create it as a table and add properties to it. When you use dotted keys, you’re essentially creating nested structures.
fruit.apple.smooth = true # This creates a 'fruit' table with a sub-table 'apple', and inside that, 'smooth' as a key
fruit.orange = 2 # Adds a new key 'orange' to the 'fruit' table
However, if you define a key with a value (like a number), you can’t later treat it as a table.
For example, this won’t work:
fruit.apple = 1 # Sets 'apple' inside 'fruit' as an integer (not a table)
fruit.apple.smooth = true # ERROR! Now 'apple' is an integer, not a table, so you can't add 'smooth' to it
In short, you can add to a table using dotted keys, but you can’t change a value into a table once it’s set.
Rule 2
You can technically use numbers in bare keys, which means you could create a dotted key that looks like a decimal or float number. For example:
3.14159 = "pi"
But, this isn’t actually a single key with a decimal point. Instead, TOML interprets this as two separate keys (3
and 14159
) under a table structure. It would look like this in JSON:
{
"3": { "14159": "pi" }
}
So, don’t use numbers like this unless you really need it, because it can be confusing. It’s better to avoid this and just use standard naming for your keys..!
Best Practices for Working with TOML Keys
Choose Descriptive Key Names
Use meaningful names to make your configuration file self-explanatory.
For example,
[server]
host = "localhost"
port = 8080
Use Dotted Keys for Flat Structures
When possible, use dotted keys to avoid overcomplicating your configurations.
server.host = "127.0.0.1"
Overusing Dotted Keys While dotted keys are convenient, excessive nesting can reduce readability.
Use Quoted Keys When Necessary
Avoid bare keys if your keys contain spaces or special characters.
"db-host" = "localhost"
Maintain Consistency
Stick to a single convention for naming and structuring keys to ensure your TOML files remain clean and consistent.
Conclusion
TOML keys form the backbone of TOML configuration files. Whether you’re dealing with simple key-value pairs, hierarchical structures, or arrays of tables, understanding the types of keys and their proper usage ensures that your configuration files remain clean, readable, and maintainable. By following best practices and avoiding common pitfalls, you can harness the full potential of TOML for your projects.
With its human-readable syntax and powerful features, TOML continues to be a favorite choice for developers seeking simplicity and clarity in their configuration files.