CLI11: The Header-Only Command Line Parser for C++
CLI11 is a command line parser for C++11 and beyond that provides a rich feature set with a simple and intuitive interface.
At a glance
- What is it?
- Parsing arguments is one of the least interesting parts of writing a C++ tool and one of the most tedious. CLI11 is a bet that it should take a dozen lines, not a page of boilerplate.
- Who is it for?
- CLI11's argument is a simple one: the boring part of your program should not be the longest part. It is header-only, dependency-free, works back to GCC 4.8, and its recent releases show the maintenance energy going into compile-time cost rather than feature churn.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 1 day 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
What CLI11 is
The repository description is plain: "CLI11 is a command line parser for C++11 and beyond that provides a rich feature set with a simple and intuitive interface." The header says the same thing more tersely, "Command line parser for C++11."
A parser like this sits between `main` and the rest of your program. You describe the options your tool accepts, the library reads `argv`, validates it, and hands you ordinary typed variables. It is a small category of software that every command line utility eventually needs and few enjoy writing themselves.
Two properties define CLI11's approach. It is header-only, meaning you copy headers or fetch them through your build system and there is nothing to link against in the traditional sense. It also has no dependencies beyond C++11 itself, a point the repository lists as a topic in its own right.
The provenance is worth knowing because it explains the design. The README says CLI11 was originally used by the GooFit GPU fitting framework and was inspired by `plumbum.cli` for Python. That heritage shows: the goal is to bring Python's readability to C++, where hand-rolled argument handling usually sprawls.
Adoption sits at roughly 4,450 stars and 470 forks, with 81 open issues against the current state. The last push to the repository was September 18, 2026, and releases in the 2.7 series landed across late July and early August, so this is an actively developed library rather than a finished artifact.
The criteria the project sets for itself
The README contains one of the more honest sections in library documentation: a checklist of what an acceptable CLI parser should do. The list is worth reading because it is also an argument for why CLI11 exists.
The first requirement is easy to include, meaning header only, one file if possible, with no external requirements. The second is short, simple syntax, and the README expands on why that matters: if most of your program is hidden in CLI parsing, that is a problem for readability.
The third sets the floor. C++11 or better, working with GCC 4.8+, which the README notes is the default on CentOS and RHEL 7, Clang 3.4+, AppleClang 7+, NVCC 7.0+, and MSVC 2015+. That is a deliberately old baseline, and it constrains what the library can use internally.
From there the requirements read like a feature list: Linux, macOS and Windows support; coverage measured by CodeCov; clear help printing; nice error messages; standard shell idioms such as grouping flags and a positional separator; correct exit codes; extensibility as part of a framework that provides applications to users; usable subcommand syntax with multiple and nested subcommands, option groups and optional fallthrough; configuration file support in TOML, INI or a custom format, with the ability to produce one as well as read one; and support for common types, simple custom types, and exotic types through extension.
One requirement stands out as a design philosophy rather than a feature. The library should "produce real values that can be used directly in code, not something you have to pay compute time to look up," which the README frames as being for HPC applications. In other words, the parsed result is a variable, not a query interface.
Installing it across build systems
There are no code fences in the documentation, which tells you something about the shape of this project. CLI11 is consumed as headers, and the repository tree reflects every packaging route you would expect.
For CMake, the tree carries `CMakeLists.txt`, a `CMakePresets.json`, and a `cmake/` directory. The 2.7.2 release notes confirm the modern path: `CLI11::Module` works for both `find_package` and `add_subdirectory`, and CMake's `fetch_content` is the modern replacement for the older `ExternalProject` pattern. Configure now fails with a clear message if CMake is older than 3.28.
Meson is supported directly, with `meson.build` and `meson_options.txt` at the root. Bazel has both `BUILD.bazel` and `MODULE.bazel`, the latter being the modern Bzlmod module file, along with a `subprojects/` directory.
The single-header route is the simplest for small projects. A `single-include/` directory at the root holds the amalgamated form, and the README notes that the library "comes in a single file form for easy inclusion in projects."
Beyond source builds, the README badges show packaging through Conan and Conda, a Repology entry, and a DOI for citation. There is also a Gitter chat link and a "Try CLI11 online" wandbox badge, which gives you a way to see the library working before you commit to it.
Options, types, and validators
The documentation's table of contents spends more space on options and validators than on anything else, and that reflects where the library puts its effort. The sections cover adding options, option types, option options, validators, default validators, validators that may be disabled, extra validators, transforming validators, validator operations, custom validators, querying validators, and getting results.
That structure tells you the library's central idea. Validation is a first-class composable object rather than an afterthought bolted onto a flag. You build a validator, apply it to an option, and the parse either succeeds or fails with a message the user can act on.
The README's feature notes mention that the library works with common types, simple custom types, and is extensible to exotic types. Option groups and fallthrough appear in the subcommand section, meaning you can structure related flags together and control whether parsing continues past a recognized subcommand.
Subclassing gets its own section, and so does formatting, which covers how help text is rendered. The "How it works" and "Unicode support" sections, including a note on using Unicode paths, suggest the authors care about the unglamorous parts.
What version 2.7 actually changed
The release history is the best evidence of where the project's attention sits, and 2.7 is unusually focused on build and compile-time cost rather than new user-facing features.
Version 2.7.0, published July 30, 2026, added a `FileSize` validator for checking minimum and maximum file sizes, a `PrefixCommandMode::PositionalOnly` that restores the pre-2.6.2 prefix command behavior as an opt-in mode where only a positional argument or the `--` separator triggers prefix mode and unrecognized options are collected as extras, and an option to write only the active subcommand defaults when generating a config file. It also carried a large set of bug fixes from what the notes describe as a systematic audit of the parsing, config, help formatting, string handling and type conversion code, along with performance work removing unnecessary copies in hot paths.
Version 2.7.1 followed the next day with a narrow fix: missing symbols in the precompiled library when built with link-time optimization. `Precompile.cpp` now explicitly instantiates `Option::ignore_case<App>` and `ignore_underscore<App>`, and the library always compiles the full validator set unless CMake disables it.
Version 2.7.2, on August 2, is the most interesting. Its stated goal is making the precompiled and experimental module modes "cheaper for clients." The changes include following include-what-you-use, moving function bodies so they compile into the library rather than into every translation unit, and having the C++20 named module import the precompiled implementation instead of the full header-only library. The module's floor dropped from C++23 to C++20.
For precompiled users specifically, 2.7.2 removed `<iostream>`, `<codecvt>`, `<iomanip>`, `<fstream>` and `<locale>` from the declaration headers, so those no longer get parsed in precompiled mode. One consequence is a source-level change: `App::exit()` is now three overloads instead of one function with stream default arguments.
How it compares to other choices
The README includes a comparison table of major C++ CLI parsers, helpfully labeled as containing biased opinions. The entry that gets the most space is Boost Program Options, described as a great library if you already depend on Boost, while noting that its pre-C++11 syntax is odd and that setting up the correct call in the main function is poorly documented, at nearly a page of code. The notes record that a simple wrapper around Boost was originally developed and then discarded as CLI11 grew more capable, and that the idea of capturing a value and setting it came from Boost Program Options.
That last detail is a nice piece of intellectual history. CLI11 is not competing with Boost so much as answering a question Boost made necessary.
Other parsers get briefer treatment. The Lean Mean C++ Options library is the next entry before the excerpt ends.
The honest summary is that if your project already pulls in Boost, using Boost Program Options is defensible and avoids a second dependency. If you want something self-contained with a syntax closer to Python, CLI11 is built for that.
Licensing, maintenance, and maturity
The repository metadata reports no license identifier, but the README badge links to a BSD license and a `LICENSE` file sits at the root of the tree. The README's own requirement list asks for a permissively licensed library, and a BSD license satisfies that. Anyone relying on this for compliance should read the `LICENSE` file directly rather than take the badge's word for it.
Maturity is the strongest argument for the library. The version numbering has reached 2.7 with a `CHANGELOG.md` at the root, and the 2.7.1 release added that changelog to the Doxygen site so users can see what changed without leaving the documentation. There are version-specific blog posts linked for 1.0, 1.3, 1.6 and 2.0, which is a long public record of design decisions.
The infrastructure signals are equally mature. The tree contains `.clang-format`, `.clang-tidy`, `.cmake-format.yaml`, `CPPLINT.cfg`, `.pre-commit-config.yaml`, `azure-pipelines.yml`, and a `.ci/` directory alongside GitHub Actions. There is a `fuzz/` directory, which means the parser is fuzzed, and a substantial `tests/` directory. The README states the project is tested on Azure and GitHub Actions, with coverage measured by CodeCov.
There is also an `AGENTS.md`, an `.agents/` directory, and a `.all-contributorsrc`. The 2.7.1 release notes mention that the release checklist was moved to a `prepare-release` skill, which is a small sign of how seriously the process is taken.
For a command line parser, the practical conclusion is that you are choosing a library with a decade of accumulated edge-case handling behind it, available in a form that costs you nothing to vendor. The main decision left is whether your project wants a single dependency at all.
Editorial conclusion
CLI11's argument is a simple one: the boring part of your program should not be the longest part. It is header-only, dependency-free, works back to GCC 4.8, and its recent releases show the maintenance energy going into compile-time cost rather than feature churn. For a C++ tool that needs to be understandable six months later, that is exactly the right direction.
Frequently asked questions
Is CLI11 header-only, and does it need any external libraries?
Yes. The README states CLI11 is header-only with no dependencies beyond C++11, and it ships a single-file form for easy inclusion. The repository root has a single-include directory holding the amalgamated header, so a small project can vendor one file.
Which C++ compilers and platforms does CLI11 support?
The README sets the floor at C++11 and lists GCC 4.8+, Clang 3.4+, AppleClang 7+, NVCC 7.0+ and MSVC 2015+. It works on Linux, macOS and Windows. Note that the C++20 named module mode requires CMake 3.28 or newer, though the regular library builds do not.
Does CLI11 support subcommands and configuration files?
Both. The README lists usable subcommand syntax with multiple and nested subcommands, option groups, and optional fallthrough. It also supports configuration files in TOML, INI or a custom format, and version 2.7.0 added the option to write only the active subcommand defaults when generating a config file.
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/cliutils-cli11)