TOML Configuration — Complete Implementation Guide
In this tutorial, you will learn about TOML Configuration. We cover key concepts, practical examples, and best practices to help you master this topic.
TOML (Tom's Obvious Minimal Language) is designed for configuration files with unambiguous syntax, explicit typing, and natural section grouping, making it an excellent choice for application configuration.
What You'll Learn
By the end of this tutorial, you will understand TOML syntax, tables and nested tables, arrays, inline tables, datetime handling, and when to choose TOML over YAML.
Why It Matters
TOML is the configuration format for Rust's Cargo, Python's pyproject.toml, and many modern tools. Its explicit syntax avoids YAML's ambiguity while remaining human-readable.
Real-World Use
DodaTech's Python Microservices use TOML for application configuration with pyproject.toml for build configuration and custom TOML files for runtime settings.
TOML Configuration Learning Path
flowchart LR
A[YAML Configuration] --> B[TOML Configuration]
B --> C[Syntax]
B --> D[Tables]
B --> E[Arrays]
B --> F{You Are Here}
style F fill:#f90,color:#fff
TOML Syntax Basics
TOML is designed to be unambiguous and map directly to hash tables.
# config.toml
title = "My Application"
[server]
port = 3000
host = "0.0.0.0"
debug = false
[database]
host = "localhost"
port = 5432
name = "myapp"
user = "app_user"
pool_size = 10
[logging]
level = "info"
format = "json"
const toml = require("@iarna/toml");
const fs = require("fs");
const config = toml.parse(fs.readFileSync("./config.toml", "utf8"));
console.log("Title:", config.title);
console.log("Server port:", config.server.port);
console.log("Database host:", config.database.host);
// Title: My Application
// Server port: 3000
// Database host: localhost
Tables and Nested Tables
Tables in TOML are defined with [section] headers.
# Database configuration with nested tables
[database]
host = "localhost"
port = 5432
[database.pool]
min = 2
max = 10
idle_timeout = 30000
[database.replication]
enabled = true
mode = "async"
# Dotted key syntax (alternative to [section] headers)
database.credentials.user = "app_user"
database.credentials.password = "${DB_PASSWORD}"
const toml = require("@iarna/toml");
const config = toml.parse(`
[database.pool]
min = 2
max = 10
[database.credentials]
user = "app_user"
`);
console.log("Pool max:", config.database.pool.max);
console.log("User:", config.database.credentials.user);
// Pool max: 10
// User: app_user
Arrays and Inline Tables
TOML supports arrays and inline tables for compact data structures.
# Array of values
ports = [8000, 8001, 8002]
allowed_origins = ["http://localhost:5173", "https://app.example.com"]
# Array of tables (array of objects)
[[databases]]
name = "users"
host = "db1.internal"
port = 5432
[[databases]]
name = "analytics"
host = "db2.internal"
port = 5432
# Inline table (compact object)
server = { host = "0.0.0.0", port = 3000, debug = false }
# Mixed
services = [
{ name = "auth", url = "http://auth:8080" },
{ name = "api", url = "http://api:8080" }
]
const toml = require("@iarna/toml");
const config = toml.parse(`
ports = [8000, 8001, 8002]
services = [
{ name = "auth", url = "http://auth:8080" },
{ name = "api", url = "http://api:8080" }
]
`);
console.log("Ports:", config.ports.join(", "));
config.services.forEach(s => console.log("Service:", s.name, "-", s.url));
// Ports: 8000, 8001, 8002
// Service: auth - http://auth:8080
// Service: api - http://api:8080
Datetime and Special Types
TOML has built-in support for datetime values with explicit types.
# Date and time
start_date = 2026-06-28
start_time = 12:00:00
start_datetime = 2026-06-28T12:00:00Z
local_datetime = 2026-06-28T12:00:00
# Numbers with underscores for readability
max_connections = 10_000
pi = 3.141_592_653
# Boolean
feature_enabled = true
maintenance_mode = false
# Multiline strings
description = """
This is a
multiline string
in TOML
"""
const toml = require("@iarna/toml");
const config = toml.parse(`
start_date = 2026-06-28
max_connections = 10_000
feature_enabled = true
`);
console.log("Start date:", config.start_date.toISOString().split("T")[0]);
console.log("Max connections:", config.max_connections);
console.log("Feature enabled:", config.feature_enabled);
// Start date: 2026-06-28
// Max connections: 10000
// Feature enabled: true
TOML vs YAML Comparison
When to choose TOML over YAML.
class TOMLvsYAML {
static compare() {
return {
toml: {
strengths: [
"Unambiguous syntax - no surprises",
"Explicit typing (no auto-detection)",
"Excellent for simple key-value config",
"Strong tooling in Rust/Python ecosystems"
],
weaknesses: [
"No anchors or aliases (more duplication)",
"Verbose for deeply nested structures",
"Limited to configuration (not data serialization)"
],
bestFor: ["Application configuration", "Build configuration", "Package metadata"]
},
yaml: {
strengths: [
"Highly readable for complex structures",
"Anchors and aliases reduce duplication",
"Widely used in cloud-native tools",
"Multi-document support"
],
weaknesses: [
"Indentation-sensitive (tab vs space issues)",
"Type auto-detection can cause surprises",
"Complex spec with edge cases"
],
bestFor: ["Infrastructure configuration", "CI/CD pipelines", "Complex nested config"]
}
};
}
}
const comparison = TOMLvsYAML.compare();
console.log("TOML best for:", comparison.toml.bestFor.join(", "));
console.log("YAML best for:", comparison.yaml.bestFor.join(", "));
// TOML best for: Application configuration, Build configuration, Package metadata
// YAML best for: Infrastructure configuration, CI/CD pipelines, Complex nested config
Common Mistakes
Not quoting strings with special characters -- TOML strings must be quoted. Unlike YAML, unquoted strings are not allowed.
Using dots in table keys without brackets -- Keys with dots need [section] syntax or dotted key notation. Bare keys cannot contain dots.
Mixing tabs and spaces -- TOML only uses spaces for formatting. Tabs inside values may cause issues.
Assuming TOML supports anchors -- TOML does not have anchors or aliases. Duplicate configuration must be repeated.
Using TOML for complex hierarchical config -- TOML becomes verbose with deeply nested structures. YAML is better for 3+ levels of nesting.
Practice Questions
How do you define an array of tables in TOML? Use [[array_name]] for each element. Each [[section]] creates a new element in the array.
What is the difference between [table] and [[table]]? [table] defines a single table (object). [[table]] defines an array of tables (array of objects).
When should you choose TOML over YAML? For application configuration with simple key-value structures, build configuration, and when working in Rust or Python ecosystems.
Challenge: Implement a TOML configuration loader that supports environment variable substitution.
class TOMLConfigLoader {
static load(filePath) {
const fs = require("fs");
const toml = require("@iarna/toml");
let content = fs.readFileSync(filePath, "utf8");
content = content.replace(/\$\{([^}]+)\}/g, (_, key) => {
return process.env[key] || "";
});
return toml.parse(content);
}
}
const config = TOMLConfigLoader.load("./config.toml");
console.log("TOML config loaded with env substitution");
FAQ
Mini Project
Build a TOML configuration loader that handles environment-specific overrides, environment variable substitution, and validation against a defined schema.
class TOMLConfigManager {
constructor(configDir = "./config") {
this.configDir = configDir;
}
load(env = process.env.NODE_ENV || "development") {
const path = require("path");
const fs = require("fs");
const toml = require("@iarna/toml");
const defaultPath = path.join(this.configDir, "default.toml");
const envPath = path.join(this.configDir, `${env}.toml`);
let config = {};
if (fs.existsSync(defaultPath)) {
config = this.parseWithEnv(fs.readFileSync(defaultPath, "utf8"));
}
if (fs.existsSync(envPath)) {
const overrides = this.parseWithEnv(fs.readFileSync(envPath, "utf8"));
config = { ...config, ...overrides };
}
return config;
}
parseWithEnv(content) {
const toml = require("@iarna/toml");
content = content.replace(/\$\{([^}]+)\}/g, (_, key) => process.env[key] || "");
return toml.parse(content);
}
}
const mgr = new TOMLConfigManager();
const config = mgr.load("production");
console.log("TOML configuration loaded");
What's Next
Now that you understand TOML configuration, learn about configuration hierarchy and precedence. Then explore secrets management.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro