TOML Tables Types Explained: A Clear and Complete Guide

Table of Contents

TOML (Tom’s Obvious, Minimal Language) is a simple configuration file format designed to be easy to read and write. It is widely used in various applications, especially in the Rust ecosystem and modern software development workflows. One of TOML’s essential features is its table structure, which organizes data efficiently.

In this guide, we’ll learn about TOML tables types, including standard, inline, and array tables. Explore their syntax, structure, and best practices for efficient TOML configuration.

What Are TOML Tables?

At the core of TOML are tables, which store data in key-value pairs. A table in TOML is defined by a header enclosed in square brackets ([]). The header marks the start of a new table, and the lines following it contain key-value pairs associated with that table. Tables can also be nested within one another, creating a hierarchical structure.

Basic Table Example

Let’s start with a simple example of a TOML file:

TOML
[fruit]
apple = "red"
orange = "orange"

Here, we have a table called [fruit], which contains two key-value pairs:

  • apple = "red"
  • orange = "orange"

TOML tables are unordered, meaning the order of key-value pairs within a table doesn’t matter. However, it’s still best practice to organize them in a logical, consistent way to improve readability.

TOML Tables Types

TOML supports multiple types of tables:

  1. Standard Tables
  2. Nested Tables
  3. Inline Tables
  4. Array of Tables
  5. Empty Tables
  6. Top-Level Tables or Root Tables
  7. Tables with Dotted Keys

Let’s go through each type in detail.

Standard Tables

These are the most common tables in TOML. They are defined using square brackets ([]) and help in grouping related configurations.

TOML
#This defines a server table with two key-value pairs.
[server]
ip = "192.168.1.1"
port = 8080

Here, server is a table containing ip and port as key-value pairs.

Nested Tables

TOML allows you to nest tables inside other tables to create hierarchical data structures.

TOML
[database]
name = "myapp"

[database.connection]
host = "127.0.0.1"
port = 3306

Here, database.connection is a nested table under database. This defines a database table containing a nested connection table. This structure makes it easy to manage related settings. The equivalent hierarchical structure would look like:

TOML
database
  ├── connection
       ├── host = "127.0.0.1"
       ├── port = 3306

JSON representation:

JSON
{
  "database": {
    "name": "myapp",
    "connection": {
      "host": "127.0.0.1",
      "port": 3306
    }
  }
}

Inline Tables

An inline table is a compact way to define key-value pairs in a single line. These are enclosed within curly brackets {} and should be used for small datasets.

TOML
#Inline Table
info = { name = "amol", age = 30, email = "[email protected]" }

Here, info is an inline table containing three key-value pairs.

Equivalent standard TOML Table Representation:

TOML
# This is equivalent to standard TOML Table (It's just for the sake of understanding)
[info]
name = "amol"
age = 30
email = "[email protected]"

Use Cases:

  • Inline tables are best for defining small, one-liner configurations.
  • They improve readability when used sparingly.

Note: Inline tables improve readability for small tables but should be avoided for large datasets.

Array of Tables

TOML also supports arrays of tables, which allow you to define multiple instances of a structured table. This is useful when you need a list of similar objects.

TOML
[[employees]]
name = "Amol"
position = "Engineer"

[[employees]]
name = "Niyati"
position = "Designer"

Each [[employees]] block represents a separate table within the array.

Equivalent JSON Representation:

JSON
{
  "employees": [
    {"name": "Amol", "position": "Engineer"},
    {"name": "Niyati", "position": "Designer"}
  ]
}

Here, we define multiple employees, each as an entry in an array.

Empty Tables

Empty tables are allowed in TOML, meaning they can exist without any key/value pairs

TOML
[empty_table]  # This table has no keys or values, and that's fine

This creates an empty table called empty_table.

Top-Level Tables or Root Tables

The top-level table (or root table) is the first section of the document. It’s unique because it doesn’t have a header (no square brackets) and defines key-value pairs directly. It starts at the very beginning of the document and ends before the first named table (or the end of the file). Unlike other tables, it is nameless and cannot be relocated.

TOML
# Top-level table starts here
name = "Lalya"
breed = "Desi Indian Dog"

# Top-level table ends here 
[owner]         # This is a separate table after the root table.
name = "Amol Pawar"
member_since = 2024-08-04

Here,

  • The root table holds the basic details, like name and breed.
  • The [owner] table follows and defines details about the dog’s owner.

Top-level tables define global information and appear before the first named table. They cannot be relocated. A top-level table is unnamed and should always be at the start of the file, before any named tables.

Tables with Dotted Keys

In TOML, dotted keys allow you to define tables at various levels within a hierarchy by using dot notation. TOML will create tables for each key part before the last one, as long as those tables haven’t already been defined.

Creating Tables with Dotted Keys

When you use dotted keys, they automatically create and define tables for each part of the key, up to the second-last part. This happens only if the tables were not previously created.

TOML
fruit.apple.color = "red"    # Creates the "fruit" table and the "fruit.apple" table

In this case, TOML interprets this as:

  • A fruit table (if it doesn’t exist).
  • A nested fruit.apple table (if it doesn’t exist).
  • A key-value pair for color inside fruit.apple.

Defining Nested Tables with Dotted Keys

When you extend the dotted keys, TOML continues creating sub-tables as needed.

TOML
fruit.apple.taste.sweet = true   # Creates fruit.apple.taste table

This results in:

  • The fruit table (if not already defined).
  • The fruit.apple table (if not already defined).
  • The fruit.apple.taste table (if not already defined).
  • The key sweet inside fruit.apple.taste with the value true.

Defining Tables and Sub-Tables: Restrictions

You cannot redefine a table that has already been created, either through a dotted key or using the [table “” not found /]

header.

Example (Incorrect/Invalid):

TOML
# Note – Considering the above examples, the table is already defined, so the following examples are invalid.

[fruit.apple]       # Invalid, because fruit.apple has already been defined
color = "green"

[fruit.apple.taste]  # Invalid, fruit.apple.taste already defined
sweetness = "high"

However, sub-tables can be added under an existing table, even if it was defined using dotted keys.

Defining Sub-Tables

If you’ve already used dotted keys to create tables, you can still use the [table “” not found /]

header to add sub-tables inside the already created tables.

TOML
[fruit]               # This is the main table.
apple.color = "red"
apple.taste.sweet = true

[fruit.apple.texture]  # Defines a sub-table for texture under apple.
smooth = true

Here,

  • The fruit table is defined with apple.color and apple.taste.sweet.
  • [fruit.apple.texture] defines a sub-table within fruit.apple, and the key smooth is set to true.

Sub-Tables and Nested Headers

If you want to define sub-tables manually, you can use the [table “” not found /]

header. A sub-table can be defined by including a table header within an existing table.

TOML
[fruit]
apple = "red"
orange = "orange"

[fruit.apple.texture]
smooth = true
rough = false

Here,

  • The main fruit table contains apple and orange entries.
  • The [fruit.apple.texture] sub-table defines properties related to the texture of apples (smooth and rough).

This feature helps to create a clear hierarchy in our configuration file, especially for more complex configurations.

Real-World Example: Fruit Configuration

In this example, we organize information about fruit using both dotted keys and [table “” not found /]

headers.

TOML
[fruit]                 # The main fruit table
apple.color = "red"
apple.taste.sweet = true
apple.size = "medium"

[fruit.apple.texture]    # A sub-table for texture within apple
smooth = true
rough = false

[fruit.orange]           # Another fruit: orange
color = "orange"
taste.sour = true

Equivalent JSON:

JSON
{
  "fruit": {
    "apple": {
      "color": "red",
      "taste": {
        "sweet": true
      },
      "size": "medium",
      "texture": {
        "smooth": true,
        "rough": false
      }
    },
    "orange": {
      "color": "orange",
      "taste": {
        "sour": true
      }
    }
  }
}

So, in general, here are the key points to remember:

  • Dotted keys automatically create tables for each key part (unless they’re already defined).
  • Tables cannot be redefined once they exist.
  • Sub-tables can be defined using [table “” not found /]

    headers within already created tables.
  • Best practice: Use dotted keys for simple cases, but use the [table “” not found /]

    header when defining sub-tables for better clarity and organization.

Conclusion

Understanding TOML tables is crucial for structuring configuration files effectively. Whether you use basic tables for simple key-value storage, nested tables for hierarchy, inline tables for compactness, or array of tables for lists, TOML provides a flexible and readable format for configurations.

By leveraging these different table types, you can create well-structured and maintainable TOML files for various applications.

Skill Up: Software & AI Updates!

Receive our latest insights and updates directly to your inbox

Related Posts

error: Content is protected !!