configor binds your C++ structs to JSON without a serialization framework
A light weight configuration library for C++
At a glance
- What is it?
- configor is a header-only C++11 configuration library whose core idea is a single macro, CONFIGOR_BIND, that tells the library how your struct maps to a json::value. It handles custom type conversion, ASCII and wide characters, and Unicode, and its plan lists YAML, ini and json5 support as unfinished, so the format story today is JSON only.
- Who is it for?
- Adopt configor if you are writing C++11 code that has to read JSON configuration into plain structs and write them back out, and you want one header-only dependency rather than a serialization framework. Do not adopt it if you need YAML, ini or json5 today, since those are listed as still to do, or if you are on a modern C++ standard where a standard library solution is more appropriate.
- 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 120 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One macro is the whole binding contract
configor is a light weight configuration library for C++11, and the design decision that makes it small is that a struct declares its own mapping in one line.
The example in the README defines a plain struct and then binds it:
struct User
{
std::string name;
int age;
// bind custom type to configor
CONFIGOR_BIND(json::value, User, REQUIRED(name), OPTIONAL(age))
};The macro takes the json value type, the struct type, and then a list of field rules. REQUIRED means the field must be present in the input, OPTIONAL means it may be absent. There is no registration step, no serializer class to derive from, and no external schema file. The binding lives next to the struct it describes, which means it is in the same file and the same review as the code that uses it.
That is the whole mechanism for custom type conversion, and it is what the README means by Custom type conversion & serialization. Once a type is bound, the library can convert in either direction, and it can do so through several representations at once.
The README also describes the library as header-only and STL-like, which are two separate claims. Header-only means there is nothing to build or link, which matters for a configuration library that would otherwise sit in your dependency graph in every binary. STL-like means the API is meant to read like a standard library rather than like a framework.
Building a json::value looks like building a std::map
The value type is designed so constructing configuration data does not feel like a framework exercise. The README's first example assigns into a value with subscript syntax and nests with chained subscripts:
json::value j;
j["integer"] = 1;
j["float"] = 1.5;
j["string"] = "something";
j["boolean"] = true;
j["user"]["id"] = 10;
j["user"]["name"] = "Leeoo";There is a second form using json::object and json::array, with brace initialisation and explicit key value pairs:
json::value j2 = json::object{
{ "null", nullptr },
{ "integer", 1 },
{ "float", 1.3 },
{ "boolean", true },
{ "string", "something" },
{ "array", json::array{ 1, 2 } },
{ "object", json::object{
{ "key", "value" },
{ "key2", "value2" },
}},
};So there are two ways to build the same thing, and they map to the two ways you would use a standard associative container. The subscript form mutates in place and is convenient for assembling a structure field by field, while the brace form is a single expression that is easier to pass around as a literal.
The key point for a configuration library is that json::value is a real value type that you can hold, pass and return, and that the array and object forms are explicit rather than inferred. Whether json::value is a reference type or a copy type is not stated in the README, and that is the kind of detail worth checking in the wiki before you rely on the copy semantics in hot paths.
The same struct converts to and from four representations
Once a type is bound, the README shows it round-tripping through four different representations, and the value of that is that a configuration source can change without your domain code changing.
// User -> json
json::value j = User{"John", 18};
// json -> User
User u = json::object{{"name", "John"}, {"age", 18}};
// User -> string
std::string str = json::dump(User{"John", 18});
// string -> User
User u = json::parse("{\"name\": \"John\", \"age\": 18}");
// User -> stream
std::cout << json::wrap(User{"John", 18});
// stream -> User
User u;
std::cin >> json::wrap(u);Four conversions, one binding. The struct goes to a json::value, and back. The struct goes to a string, and back through json::parse. The struct goes to a stream, and back through operator>> on the wrapped value.
The naming makes the mechanism visible. json::dump and json::parse are the string pair, and json::wrap is the stream pair, so the wrapped form is what you use when a value should participate in stream operators directly.
That last one is the practical payoff for configuration loading. A program that reads its configuration from standard input can use the same struct and the same binding as the one it reads from a file, because the conversion is expressed in terms of streams rather than in terms of a specific file format. A library that only offered parse and dump would push that decision back onto the caller.
Unicode and wide characters are a feature, not an afterthought
The feature list calls out Complete Unicode support and ASCII & Wide-character support as two separate entries, and that pairing is deliberate.
The ASCII and wide-character item is about the character types the library accepts, so a std::string and a std::wstring can both be read into a bound struct. On Windows, where the native wide character type is UTF-16, that difference is not academic, and a configuration library that hardcoded one of them would force a conversion at every call site.
Complete Unicode support is a separate claim about the encoding of the data itself rather than the type of the container. Combined with the repository topics, which list configuration, cpp and json, the picture is a JSON library that treats text encoding as a first class concern.
This matters for configuration specifically. A configuration file is one of the few places where a non-ASCII string is completely ordinary, since it holds paths, display names, and service identifiers as often as it holds numbers and flags. Getting the encoding wrong produces a file that parses but contains mangled values, and the failure shows up in the running application rather than at load time.
The wiki is where the details live, since the README covers the API surface and links to it for more, and it also mentions a Chinese version of the readme alongside the English one, which is a reasonable signal about the author's audience.
The plan says JSON only, and says so plainly
The Plan section in the README is a checklist with three items ticked and five not, and it is the most useful thing in the file for an adopter.
Done are custom type conversion, Unicode support, and unit test coverage above 85 percent. The coverage figure is specific enough to be checkable, and it lines up with the repository contents, since there is a tests/ directory and the README carries both a GitHub workflow badge for unit tests and a codecov badge.
Not done are improve error message, YAML support, ini support, json5 support, and a SAX tool.
Read that list carefully if your configuration is not JSON. YAML and ini are not on the roadmap as shipped, they are items in a plan, and json5 is the same. The SAX tool would matter if you need to process a large document incrementally, which for a configuration file is usually not the case, but it is a signal about the library's intended scale.
The improve error message item is the one to notice, because it is a known gap rather than a missing format. A configuration library whose error messages are known to need improvement will still parse correctly, but a malformed file will produce a less helpful diagnostic than you would like, and the error is likely to surface as a missing required field rather than as a precise report of which line and key were wrong.
The repository layout backs the picture up. There is a CMakeLists.txt, a cmake/ directory, an include/ directory, a tests/ directory and an examples/ directory with a CMakeLists.txt, a main.cpp, a handler.h and a user_info example with its own header, plus a .clang-format, an .editorconfig and a codecov.yml.
The release record has a gap, and the licence is the simple part
The maintenance picture needs reading carefully, because the two signals point in different directions.
The release history shows v0.9.21 on 2022-09-29, v0.9.20 on 2022-09-27 and v0.9.19 on 2022-09-16. Three patch releases inside two weeks, then nothing for a long stretch. The last push to the repository was on 2026-06-25 and the repository is not archived, so the code has moved since the last tag without a new release being published on GitHub.
The practical reading is that the library is stable in shape but not actively released. The version number has not left the 0.9 series, which in itself signals an API that has not been declared final, and a project with no tags in nearly four years is a dependency whose upstream maintenance you cannot assume from the version number alone.
The upstream situation matters more than usual for a header-only library, because a header-only library is copied into your build. If upstream publishes a fix, you get it only when you update the vendored copy, and there is no package manager upgrade to force the question.
The licence is MIT, which is the simple part. The README badge and the repository listing both record MIT, and there is a LICENSE file at the root. A permissive MIT grant means no copyleft obligation on the code you build with it, which is a licensing note rather than legal advice.
The remaining consideration is scope rather than licence. A library this small that does one thing well is a good candidate for vendoring into a codebase that has no appetite for another dependency, and the fact that it is header-only makes that a single directory copy rather than a build integration. The question to ask is whether you want to own a copy of a project whose published releases stopped in 2022, and if the answer is yes, the test suite in the repository is the thing that tells you whether the copy still passes.
Editorial conclusion
Adopt configor if you are writing C++11 code that has to read JSON configuration into plain structs and write them back out, and you want one header-only dependency rather than a serialization framework. Do not adopt it if you need YAML, ini or json5 today, since those are listed as still to do, or if you are on a modern C++ standard where a standard library solution is more appropriate. Verify first that the header-only build fits your include and link model, that the fields you mark REQUIRED and OPTIONAL match your actual data, and whether the upstream releases, which stop at v0.9.21 from 2022, still apply to the code you are looking at, since the last push was on 2026-06-25.
Frequently asked questions
How do I bind a C++ struct to JSON with configor?
Declare the struct and add a single CONFIGOR_BIND line naming the json::value type, your struct type, and the field rules, for example CONFIGOR_BIND(json::value, User, REQUIRED(name), OPTIONAL(age)). There is no separate registration step and the binding lives next to the struct.
Can configor read configuration from YAML or ini files?
Not yet. The README plan lists YAML support, ini support and json5 support as unchecked items, alongside a SAX tool and improved error messages. The format supported today is JSON.
What does configor depend on and how do I use it?
It is a header-only C++11 library with an STL-like API and no separate build step, and the repository is built with CMake through a CMakeLists.txt and a cmake/ directory. The README links to the project wiki for the full usage details.
What is the current version and maintenance state of configor?
The published releases are v0.9.19, v0.9.20 and v0.9.21, the last of them on 2022-09-29, and the repository has no releases since then. The last push was on 2026-06-25 and the repository is not archived, and the licence is MIT.
Official sources
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.
[](https://hysenlabs.com/projects/nomango-configor)Was this useful?