Back to Blog
Python

Read, Modify, and Write TOML with Python tomlkit

python tomlkit read modify and write toml: Learn how to read, modify, and write TOML files with Python's tomlkit library while preserving comments, key order, and form...

tomlkitTOMLconfiguration filespyproject.tomlPython
Illustration of a TOML configuration file being edited with Python's tomlkit library while preserving its comments and formatting.

python tomlkit read modify and write toml requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

Reading, modifying, and writing TOML files in Python with tomlkit is a common task for configuration tooling, and the library is designed specifically to preserve the original formatting of the file. The standard library's tomllib module can parse TOML, but it returns plain dictionaries and cannot serialize them back to TOML. tomlkit parses TOML into a document object that behaves like a dictionary while retaining comments, key order, and whitespace, so editing a pyproject.toml or a config.toml does not destroy the formatting that other tools or humans rely on.

Why tomlkit Exists

Python 3.11 added tomllib to the standard library, but it only covers the read side. Parsing a file with tomllib produces a plain dict, and there is no built-in way to write that dict back as TOML. If you want to modify a value and save the file, you have to serialize with a third-party library, and the result is a valid but completely reformatted file: comments are gone, key order follows insertion order, and any deliberate formatting choices are lost.

tomlkit solves this by keeping the original document structure in memory. It stores each key, value, comment, and piece of whitespace as part of the parsed tree. When you change one value, the rest of the document keeps its original layout. This is why tooling like Poetry uses tomlkit to edit pyproject.toml files: a small version bump should not reformat the entire file.

Reading a TOML Document

tomlkit provides two entry points for reading:

  • tomlkit.parse(text) parses a string.
  • tomlkit.load(file_obj) reads from an open file object.
import tomlkit with open("pyproject.toml", "r", encoding="utf-8") as f: doc = tomlkit.load(f) print(doc["tool"]["poetry"]["name"])

The returned object is a TOMLDocument, which behaves like a mapping. You access values with the same subscript syntax you would use on a dictionary, including nested tables. Unlike a plain dictionary, the document remembers where each key appeared, what whitespace surrounded it, and which comments belong to it.

If you already have the file contents as a string, parse is the direct equivalent:

doc = tomlkit.parse(text)

Both return the same TOMLDocument type, so everything that follows applies to either approach.

Modifying Existing Values

Modifying a value is a plain assignment:

doc["tool"]["poetry"]["version"] = "2.1.0"

When you assign a Python value, tomlkit converts it to the appropriate internal TOML type and replaces the existing item in place. The comment attached to that key stays where it was. If the original file contained:

# Current release version version = "2.0.0"

then after the assignment the comment remains above the version key, and only the value changes.

The same applies to booleans, integers, floats, arrays, and dates:

doc["tool"]["poetry"]["dependencies"]["requests"] = "^2.32.0" doc["tool"]["poetry"]["authors"] = ["Alice <alice@example.com>"]

If the key already exists, its trivia is preserved. If it does not exist, the new key is appended at the end of the current table.

Adding New Keys, Tables, and Arrays

Adding a new scalar key uses the same assignment syntax:

doc["tool"]["poetry"]["description"] = "A command-line tool for syncing files"

For a new empty table, use tomlkit.table():

from tomlkit import table doc["tool"]["newtool"] = table() doc["tool"]["newtool"]["enabled"] = True

For an array that you build incrementally, use tomlkit.array():

from tomlkit import array items = array() items.append("one") items.append("two") doc["tool"]["newtool"]["items"] = items

For an inline table, use tomlkit.inline_table():

from tomlkit import inline_table cfg = inline_table() cfg["retries"] = 3 cfg["timeout"] = 30 doc["tool"]["newtool"]["config"] = cfg

One important limitation: assignment to a nested path requires every intermediate table to already exist. The following raises a KeyError if tool or newtool is missing:

doc["tool"]["newtool"]["enabled"] = True

Create the intermediate tables first, or check for their presence before assigning.

Writing the Modified Document Back

Two functions write a document:

  • tomlkit.dump(doc, file_obj) writes to an open file object.
  • tomlkit.dumps(doc) returns the TOML as a string.
with open("pyproject.toml", "w", encoding="utf-8") as f: tomlkit.dump(doc, f)

If you need the string for another purpose, such as sending it over HTTP or embedding it in a larger file, use dumps:

updated = tomlkit.dumps(doc)

The serialized output preserves the original comments, key order, and whitespace, with only the modified or added sections reflecting the changes.

How Formatting and Comments Are Preserved

The reason tomlkit can round-trip a file without reformatting it is that every item in the document carries its own trivia. Trivia includes the leading whitespace and blank lines before a key, the trailing whitespace after a value, and any comments attached to the key, whether they appear on the same line or on lines above it.

When you replace a value, the new value inherits the trivia of the old one. When you add a new key, you can attach a comment explicitly:

doc["tool"]["newtool"]["enabled"] = True doc["tool"]["newtool"]["enabled"].comment("Enable the new tool")

The .comment() method attaches a comment that will be written on the line above the key during serialization.

This behavior is what makes tomlkit suitable for editing files that are shared with other tools. A pyproject.toml often contains comments explaining why a dependency is pinned or why a setting exists. Those comments survive a tomlkit edit, which is not the case when you parse with tomllib and serialize with a generic TOML writer.

Choosing Between tomlkit and tomllib

Capabilitytomlkittomllib
Read TOMLYesYes
Write TOMLYesNo
Preserve commentsYesNo
Preserve key orderYesNo
Availabilitypip install tomlkitPython 3.11+

Use tomllib when you only need to read configuration and never write it back, and when comments and ordering do not matter. It is part of the standard library and parses faster because it builds a plain dictionary rather than a rich document tree.

Use tomlkit when you need to modify and write TOML, or when preserving the original formatting matters. The extra parsing cost is negligible for typical configuration files, which are usually a few kilobytes. For very large files parsed repeatedly in a hot path, tomllib may be preferable, but that scenario is uncommon for TOML configuration.

tomlkit is a pure-Python package installed with pip. It implements the TOML 1.0 specification, so it handles the same syntax that tomllib accepts. Because it keeps a richer in-memory representation, it is the practical choice whenever a script must edit a TOML file in place rather than regenerate it from scratch.

python tomlkit read modify and write toml: Practical Usage a | RYUSLOG DEV