Library / SDK
marzer/tomlplusplus avatar
marzer/tomlplusplus

toml++: a TOML parser for C++ that also writes JSON and YAML

Header-only TOML config file parser and serializer for C++17.

2,167 stars217 forksC++MIT

At a glance

What is it?
toml++ is an MIT licensed, C++17 TOML parser and serializer available as a single header or a regular library, passing the official toml-test suite. The interesting part is what it gives you beyond parsing.
Who is it for?
toml++ earns its place in a C++ project when you want one dependency that reads config, can re-emit it as JSON for a tool that only speaks JSON, and carries no transitive baggage. The single-header route makes it close to free to adopt, and the MIT licence leaves nothing to negotiate.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 83 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One dependency that reads TOML and writes the other two formats

The feature list leads with the obvious thing, a TOML parser and serializer for C++17, and then keeps going in a direction most libraries in this space do not. toml++ can serialize to JSON and YAML as well as TOML, which means the same in-memory document can be handed to a tool that speaks JSON without a second parser or a conversion step in your code.

The rest of the list is careful about constraints, which is the more telling part. It does not require RTTI. It works with or without exceptions. It handles UTF-8 properly including a byte order mark. It is C++17, with some C++20 features used where available such as experimental `char8_t` string support, and the repository topics name both `cplusplus-17` and `cplusplus-20`. The supported-compiler claim is Clang 8 and up, GCC 8 and up, and MSVC from VS2019, tested on x64, x86 and ARM.

Two compatibility claims deserve a note. It supports the latest TOML release, v1.0.0, plus optional support for some unreleased TOML features, so you can experiment ahead of the spec at the cost of depending on draft behaviour. And it passes all tests in the official toml-test suite, which is the reference conformance suite rather than the author's own tests. That matters more than a feature bullet, because a TOML parser either agrees with the spec on edge cases or it does not.

Parsing a config file takes about ten lines

The README's example is deliberately terse, and that is a fair reflection of the library. Parsing a file and pulling typed values out of it:

cpp
#include <toml++/toml.hpp>

using namespace std::literals;

auto config = toml::parse_file( "configuration.toml" );

// get key-value pairs
std::string_view library_name = config["library"]["name"].value_or(""sv);
std::string_view library_author = config["library"]["authors"][0].value_or(""sv);
int64_t depends_on_cpp_version = config["dependencies"]["cpp"].value_or(0);

The API design point here is that indexing does not throw on a missing key. `config["library"]["name"]` walks tables, and `value_or` supplies the default when the value is absent, so a config file missing an optional entry produces your fallback rather than an exception. That behaviour pairs with the no-exceptions support, since code that compiles without exceptions cannot rely on throwing to report absent keys.

The rest of the example covers mutation and iteration. You insert or assign into the document, then walk it with `for_each` taking a lambda over heterogeneous key and value pairs, or with a ranged-for if you prefer the traditional shape. The comment in the README about using a visitor for heterogeneous data is the right framing, because a TOML document can mix strings, integers, arrays and tables at the same level and you need a compile-time branch to handle that, which is what `if constexpr (toml::is_string<decltype(value)>)` is doing in the sample.

Single header or regular library, same API either way

The README describes two flavours and states plainly that the API is identical for both. The single-header version is a matter of dropping `toml.hpp` into your source tree, with the note that there is no step two. The regular version means adding `tomlplusplus/include` to your include paths, and optionally `tomlplusplus/modules` as well with `TOMLPLUSPLUS_BUILD_MODULES` enabled for module support.

The upstream feature list describes toml++ as header-only with a parenthetical optional, which is the accurate way to put it. The header is the source, but the repository also builds a compiled library, and the presence of `meson.build`, `meson_options.txt`, `CMakeLists.txt` and `cmake/` in the tree confirms two real build paths rather than a convenience shim.

There are also a Visual Studio project and a debug visualizer in the tree, in the form of `toml++.sln`, `toml++.vcxproj` and `toml++.natvis`. The last of those is a nice touch for anyone debugging: it tells Visual Studio how to display toml++ objects natively in the debugger, which removes a lot of the pain of stepping through a document tree with a custom value type.

Every build system in the ecosystem, in one table

Where toml++ documents dependency management is more thorough than most single-header libraries bother to be. It gives you Conan, DDS for JavaScript projects, tipi.build, VCPKG, Meson, CMake FetchContent and plain Git submodules. That is a deliberate response to the C++ packaging situation, and the author says so with unusual candour, describing the ecosystem as a fractal nightmare of unbridled chaos and declining to keep up with all available options.

The CMake route is the most common for C++17 projects, and the recipe is short enough to paste:

cmake
include(FetchContent)
FetchContent_Declare(
    tomlplusplus
    GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
    GIT_TAG        v3.4.0
)
FetchContent_MakeAvailable(tomlplusplus)

The Meson equivalent is one line, `tomlplusplus_dep = dependency('tomlplusplus')`, after `meson wrap install tomlplusplus`, and it can also be used as a subproject directly. VCPKG users get `vcpkg install tomlplusplus`, and the DDS entry for a `package.json5` is the string `tomlpp^3.4.0`.

Notice that every documented pin points at 3.4.0, whether Conan, DDS, or the FetchContent tag. That is consistent with the tagged release, and it is the detail to keep in mind when you decide which version to depend on.

Build-time behaviour is set with preprocessor defines

Configuration is handled through preprocessor macros that you set before including the library, and the README's own position is that you will probably never need to touch them. The table it opens lists them by type and default, and the visible rows include `TOML_ASSERT(expr)` for swapping the assert function, `TOML_CALLCONV` for applying a calling convention to exported functions, `TOML_CONFIG_HEADER` for pulling in your own header ahead of the library, and `TOML_DISABLE_CONDITIONAL_NOEXCEPT_LAMBDA` for MSVC's legacy lambda processor, which defaults to `0`.

That last one is the kind of entry that exists because someone hit a real compiler bug, and it is a fair signal of the level of care in the rest of the library. The same is true of the changelog for v3.4.0, which lists fixes for NVCC compilation errors, for `for_each()` failing to compile on GCC 7 or lower, for an `FLT_RADIX` check broken by Intel MKL headers, and for keys containing tab characters incorrectly formatting as bare keys or failing to round-trip. Those are specific enough to be useful.

The round-trip bug is worth pausing on for a configuration parser. A library that reads and writes config files will eventually write a file a human edits, and if it changes how a key is quoted on the way out, you get spurious diffs in version control. The fact that this was fixed and that the `toml-test` suite is run suggests the author treats fidelity as part of the contract.

A 2023 release tag with development continuing into 2026

The version numbers tell a story that is worth checking before you pin anything. The newest tagged release is v3.4.0, published on 2023-10-13. The last push to the repository was on 2026-07-21, and the default branch is `master`. Both facts are in the repository as published, and the gap between them is nearly three years.

That gap has a practical reading. If you need a released, dated artifact for a build system or a supply chain audit, v3.4.0 is what exists, and the README's own integration examples point at exactly that version. If you want the fixes that landed after the tag, you are tracking the branch head and accepting that it moves. Both are legitimate choices, but they should be deliberate rather than accidental, and it is worth reading the CHANGELOG.md in the tree to see what falls between the tag and the head.

The repository also carries things you would not find in a thin wrapper. There is a `fuzzing/` directory, which tells you parser input has been fuzzed rather than merely unit tested. There is a `tests/` directory, a `toml-test/` directory that is the conformance suite as a submodule, and a `tools/` directory for repository tooling. There is `vendor/` for third-party code and `.tipi/` for the tipi.build integration. That is the shape of a project where correctness is treated as the product rather than a nice-to-have.

Editorial conclusion

toml++ earns its place in a C++ project when you want one dependency that reads config, can re-emit it as JSON for a tool that only speaks JSON, and carries no transitive baggage. The single-header route makes it close to free to adopt, and the MIT licence leaves nothing to negotiate. Two things to check before committing. The latest tagged release is v3.4.0 from 2023-10-13, while commits have continued into 2026, so decide whether you want a tagged version or the branch head, because they are not the same thing. And if you rely on custom build flags, read the configuration table and the homepage rather than guessing at macro names, since that table is where the library exposes its behaviour and the README only gives you its opening rows.

Frequently asked questions

What is tomlplusplus in C++?

It is a header-only TOML parser and serializer for C++17, MIT licensed, that also serializes to JSON and YAML. It supports the TOML v1.0.0 spec plus some unreleased features, and passes the official toml-test suite.

How do I add toml++ to a CMake project?

Use FetchContent to declare the repository and make it available, which the README shows with GIT_TAG pinned to v3.4.0. If you prefer a package manager, the README also documents VCPKG, Conan, Meson wrap and DDS integration.

How does toml++ compare with toml11 and cpptoml?

The README itself names cpptoml and toml11 as alternatives and prints them into a config example, so they are the direct competitors in this space. The differentiators toml++ lists are conformance with the toml-test suite, JSON and YAML output, module support, and no RTTI requirement.

Does toml++ require exceptions or RTTI?

No. The feature list states it does not require RTTI and works with or without exceptions. Missing keys are handled by value_or returning a supplied default rather than by throwing.

Which compilers does toml++ support?

The README states it is tested on Clang 8 and later, GCC 8 and later, and MSVC from VS2019, across x64, x86 and ARM. It targets C++17, using some C++20 features where available such as experimental char8_t support.

Official sources

  1. License: MIT
  2. marzer/tomlplusplus on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/marzer-tomlplusplus.svg)](https://hysenlabs.com/projects/marzer-tomlplusplus)