Library / SDK
jinja2cpp/Jinja2Cpp avatar
jinja2cpp/Jinja2Cpp

Jinja2Cpp: running Jinja2 templates inside a C++ program

Jinja2 C++ (and for C++) almost full-conformance template engine implementation

602 stars115 forksC++MPL-2.0

At a glance

What is it?
Jinja2Cpp is a C++ implementation of the Jinja2 template engine, aimed at programs that need dynamic HTML pages or source code generation without a Python runtime in the process. It supports most of the Jinja2 statement set, and the readme is careful to say the conformance is almost full rather than complete, with a compatibility table linked for the details.
Who is it for?
Jinja2Cpp fits a C++ application that has to produce HTML or source code from templates, and wants the Jinja2 syntax and filter library without embedding Python. It does not fit a project that needs the very latest Jinja2 features, since the readme states the current support is limited to a subset and points to a compatibility table.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository received new commits within the last day.
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 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: templates without a Python runtime in the process

Jinja2C++ is a C++ implementation of the Jinja2 Python template engine, and the readme states the purpose plainly: this library brings support of powerful Jinja2 template features into the C++ world, reports dynamic HTML pages and source code generation.

That is a real need. Jinja2 is a good template language, and if your program is a C++ service, a game, a desktop tool or a code generator, your options are usually to embed Python, to shell out to a Python process, or to reimplement the template language. Jinja2Cpp is the third option done seriously.

The feature list shows the scope of the work rather than a thin wrapper. There is an easy-to-use public interface where you just load templates and render them, conformance to the Jinja2 specification, full support of narrow and wide character strings for both templates and parameters, built-in reflection for the common C++ types plus the nlohmann and rapid JSON libraries, and powerful full-featured Jinja2 expressions with filtering via the pipe operator and if-expressions.

Control statements are covered too, with set, for, if, filter, do and with. On top of that come templates extension, including and importing, macros, rich error reporting, and a shared template environment with a templates cache support.

The audience is a C++ developer who already has Jinja2 templates, or a team deciding which template syntax to standardise on, and who does not want a Python dependency in the deployment.

The API: load, render, and check the result

The public interface is small, and the example in the readme shows all of it:

c++
#include <jinja2cpp/template.h>

std::string source = R"(
{{ ("Hello", 'world') | join }}!!!
{{ ("Hello", 'world') | join(', ') }}!!!
{{ ("Hello", 'world') | join(d = '; ') }}!!!
{{ ("Hello", 'world') | join(d = '; ') | lower }}!!!
)";

Template tpl;
if (auto loaded = tpl.Load(source); !loaded)
    std::cerr << loaded.error() << std::endl;

std::string result = tpl.RenderAsString({}).value();

The three steps are declare a Template, load the template text into it, and render it. The example deliberately exercises the filter syntax: a tuple piped through join with no arguments, then with a separator, then with a keyword argument, and finally with lower applied on top of the join, which shows that filters compose.

The error handling is the part worth understanding before you write code against it. The readme states that Load and Render return a jinja2::Result that holds the error when they fail, and that they are marked [[nodiscard]], meaning you must check the result rather than drop it. The example does exactly that with an if statement that prints loaded.error() to standard error, and the feature list calls out rich error reporting as a headline capability, which matters for a template engine because a template error is usually a user input error rather than a programming error.

The usage documentation notes that RenderAsString is called with an empty parameter map in the example, and the parameters type is what carries your own values into the template.

What is actually implemented, and where the gaps are

The readme is unusually honest about conformance, which is the section a potential adopter should read first.

It says that currently Jinja2C++ supports a limited number of Jinja2 features, and that it is planned to be a fully specification-conformant implementation. The current support covers expressions, in almost every style, simple, filtered, conditional and so on. It covers a long list of filters, including sort, default, first, last, length, max, min, reverse, unique, sum, attr, map, reject, rejectattr, select, selectattr, pprint, dictsort, abs, float, int, list, round, random, trim, title, upper, wordcount, replace, truncate, groupby, urlencode, capitalize, escape, tojson, striptags, center and xmlattr. The testers are supported too, with eq, defined, ge, gt, iterable, le, lt, mapping, ne, number, sequence, string, undefined, in, even, odd, lower and upper, and the functions range and loop.cycle.

The statement list is the other half: the if statement with elif and else, the for statement with else branch and if part support, include, import and from, set in both line and block form, filter, extends and block, macro and call, with, the do extension, recursive loops, and space control with raw and endraw blocks.

The link to the compatibility table at the Jinja2Cpp documentation site is where to verify the specific features you use. The readme's phrasing, limited to a subset and planned to become fully conformant, is a fair summary: this is a substantial implementation of Jinja2, not a complete one, and a project that depends on a specific filter or statement should check before committing.

Build requirements: C++17, Boost, fmt and expected-lite

Jinja2C++ requires C++17. C++17, C++20 and C++23 are supported and tested, and C++26 is built in CI as a forward compatibility check. The readme is precise about how that reaches your build: the CMake target requires cxx_std_17 publicly, so CMake consumers get at least C++17 automatically, while others need -std=c++17, with GCC up to 10 and Clang up to 15, or /std:c++17 for MSVC, whose default is still C++14. Version 1.x was the last to support C++14.

That MSVC detail is the kind of thing that costs a day if you discover it late, because the default compiler flags will not give you the language level the library needs.

The external dependencies are listed as boost library at least version 1.75, nonstd::expected-lite, and fmtlib::fmt. There is a documentation page explaining why each dependency is needed, which of them are optional, and the CycloneDX and SPDX SBOMs that ship with the package.

The distribution channels are visible in the badges: a Conan package in conan-center, and a pkg-config file template at the root, jinja2cpp.pc.in, which means a system install is usable from any build system that understands pkg-config.

The test matrix is wide, and each pull request is built and tested with Linux GCC 12 and 14 and Clang 18 and 20 at C++17, C++20 and C++23, with C++26 on GCC 14 and Clang 20, macOS 14 and 15 with Apple Clang at the same three standards, and Windows with MSVC 2022 x64 at C++17, C++20 and C++23, using /std:c++latest until MSVC ships /std:c++23.

Getting started, and the three steps it takes to link against it

The getting started section lists what you have to do to use Jinja2C++ in your project, and it is a short list.

You clone the Jinja2C++ repository, you build it according to the instructions in the build and install documentation, and you link to your project. The build step is not a package manager install, so the practical route for a consumer is either to vendor it as a subdirectory and build it as part of your own CMake project, or to build and install it system wide and point your build at it.

Once linked, the usage sequence is three steps. Declare the object:

c++
jinja2::Template tpl;

Populate it with the template text:

c++
auto loaded = tpl.Load("{{ 'Hello World' }}!!!");

and render it:

c++
std::cout << tpl.RenderAsString({}).value() << std::endl;

which produces Hello World!!!

The readme ends that section with a blunt That's all!, and points to the usage documentation for more detailed examples and feature descriptions. There is also a separate documentation page for the Jinja2 specification support and compatibility table, which is the page to consult before you start.

One design point to note in the loading step: Load takes the template source as a string, not a file path. File handling and the shared template environment with a cache, which the feature list mentions, are how you avoid re-parsing the same template on every request, and that is the piece that turns this from a toy into something usable in a server.

Where the project stands, and the licence question

The licence is MPL-2.0, the Mozilla Public License, and the repository badge points at the LICENSE file. MPL is a file-level copyleft: if you modify a file of the library, your changes to that file must be published under the same licence, while using the library in your own application does not oblige you to release the application. That is a much lighter obligation than a whole-program copyleft, and it is a reasonable fit for a library that people will vendor and patch. This is a description of how the licensing is arranged and not legal advice.

On activity, the repository is not archived, the last push was on 2026-10-19, and the recent releases are 1.3.2 from 2024-06-23, 1.3.1 from 2023-11-19 and a 1.3.0 beta from the same day. So the code is being worked on now while the last published release is from mid-2024, and the working version is ahead of the packaged one.

That gap is worth factoring into an adoption decision. If you build from the repository, you get the current work but you own the build integration. If you take the published 1.3.2, you get a stable artifact that predates the recent fixes, and the changelog in the repository is where you would find out what changed.

The repository layout also shows a project that takes its own quality seriously. There is a fuzz/ directory, a bench/ directory, a test/ directory, a clang-tidy configuration and a clang-format configuration, an abi/ directory, an sbom/ directory, a conanfile.txt, a cmake/ directory, a thirdparty/ directory, and a REVIEW.md alongside AGENTS.md and CLAUDE.md. The ABI directory and the SBOMs are the two that signal a project being consumed by other companies' build pipelines.

Editorial conclusion

Jinja2Cpp fits a C++ application that has to produce HTML or source code from templates, and wants the Jinja2 syntax and filter library without embedding Python. It does not fit a project that needs the very latest Jinja2 features, since the readme states the current support is limited to a subset and points to a compatibility table. Before adopting it, check that table against the templates you already have, and confirm the build instructions for your platform, because the library needs Boost, fmt and expected-lite and is compiled rather than installed from a package.

Frequently asked questions

What is Jinja2Cpp and what problem does it solve?

It is a C++ implementation of the Jinja2 Python template engine, bringing Jinja2 template features into the C++ world for dynamic HTML pages and source code generation. It is aimed at programs that want Jinja2 syntax and filters without embedding a Python runtime.

How do I load and render a template with Jinja2Cpp?

Declare a jinja2::Template, load the template source into it with Load, and render it with RenderAsString. Load and Render return a jinja2::Result that holds the error when they fail, and they are marked [[nodiscard]], so you must check the result rather than drop it.

Is Jinja2Cpp fully conformant with the Jinja2 specification?

Not yet. The readme says the current support is limited to a subset covering expressions, a long list of filters and testers, the main control statements, template inheritance, macros and recursive loops, and it points to a compatibility table on the documentation site for the details.

What does Jinja2Cpp need to build?

C++17 at minimum, with C++20 and C++23 supported and tested, plus the boost library at version 1.75 or later, nonstd::expected-lite and fmtlib::fmt. The CMake target requires cxx_std_17 publicly, and non-CMake users need -std=c++17 or /std:c++17 for MSVC.

What licence is Jinja2Cpp released under?

MPL-2.0, the Mozilla Public License, with the LICENSE file at the root of the repository. The project is not archived, the last push was on 2026-10-19, and the recent releases are 1.3.2 from 2024-06-23, 1.3.1 from 2023-11-19 and a 1.3.0 beta from 2023-11-19.

Official sources

  1. jinja2cpp/Jinja2Cpp on GitHub
  2. License: MPL-2.0
  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/jinja2cpp-jinja2cpp.svg)](https://hysenlabs.com/projects/jinja2cpp-jinja2cpp)

Was this useful?