ngtcp2 is QUIC as a library, and the examples are the interesting part
ngtcp2 project is an effort to implement IETF QUIC protocol
At a glance
- What is it?
- ngtcp2 implements the IETF QUIC protocol defined in RFC 9000, as a C library that depends on no external libraries at all, with example clients and servers written in C++23 and a set of example programs that talk HTTP/3 and the HQ protocol used by the interop runner. What the project spends most of its documentation on is not the protocol but the build matrix, because the library needs a TLS backend and the examples need nghttp3 and libev.
- Who is it for?
- ngtcp2 is the right codebase for a team that needs to embed QUIC in something that is not a browser or a CDN, because the library itself has no dependencies, the C API is the product, and the examples show how the pieces are meant to be wired together rather than hiding that behind a framework. It is the wrong project for someone who wants a QUIC server in an afternoon, because the TLS backend has to be chosen, built and configured by hand.
- 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 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A protocol library, not a server product
The project describes itself as an effort to implement the RFC 9000 QUIC protocol, and it opens with the line that explains the design, a call it TCP/2, one more time. The thing worth noticing in the repository is where the boundary is drawn. The libngtcp2 C library itself does not depend on any external libraries, and it requires a C11 compiler to build, with modern compilers such as clang 19 or newer, gcc 15 or newer, and MSVC 2022 known to work. The example client and server are written in C++23 and should compile with the same modern C++ compilers. That split is the architecture in one paragraph. The library is the deliverable, it is small, it has no opinions about your event loop, your TLS stack or your HTTP/3 implementation, and the examples exist to prove the library works and to show the shape of a real integration. The topics the repository carries make the scope plain as well, with rfc9000, rfc9001, rfc9002, rfc9221, rfc9287, rfc9368 and rfc9369, which are the transport, TLS, datagram and related specifications.
The TLS backend is the real dependency decision
The ngtcp2 crypto helper library, and the client and server under the examples directory, require at least one of the listed TLS backends. quictls is there and marked deprecated. GnuTLS 3.7.5 or newer works. BoringSSL at a specific commit, 22a0079b189c391b95689813a41982ce11876f0a, or aws-lc 1.39.0 or newer. Picotls at a specific commit. wolfSSL 5.5.0 or newer. LibreSSL v3.9.2 or newer. And OpenSSL 3.5.0 or newer, marked experimental. The reason there is a list rather than a recommendation is that QUIC does not use TLS the way HTTP/2 does, since the handshake and the key updates are integrated into the protocol's own state machine, so a TLS library has to expose what QUIC needs, and only some of them do. The pins to specific commits for BoringSSL and Picotls are the tell, since a commit pin means the QUIC-specific patches live in that tree, which is why the build instructions are per backend rather than one set of flags.
The examples need nghttp3 and libev on top of a TLS backend
To build the sources under the examples directory, libev and nghttp3 are required, nghttp3 being the HTTP/3 implementation and the HTTP/3 project from the same organisation. The example tree makes the structure clear, with separate source files for the HTTP/3 codec on both the client and the server side, the HQ protocol codec on both sides, a client, a server, a client base and a server base, plus http.cc and network.h. The two protocol codecs sitting side by side are the interesting part, because the HQ protocol is a minimal protocol specifically tailored for the quic-interop-runner, and the fact that the same client and server bases can speak either is what makes the interop testing possible. On the toolchain side, the example programs also use a TLS certificate compression feature in the BoringSSL and aws-lc examples, and that needs libbrotli-dev 1.0.9 or newer.
Building from git starts with the submodules
The build instructions come as one section per TLS backend, and the first step is the same in every case. When building from git, you pull the submodules:
git submodule update --initAfter that, the per-backend script runs. The wolfSSL route clones a pinned stable tag, runs autoreconf, configures with a long list of flags, makes and installs, then does the same for nghttp3, and then configures ngtcp2 itself with the pkg-config path pointing at the two installed libraries:
git clone --depth 1 -b v5.9.2-stable https://github.com/wolfSSL/wolfssl
cd wolfssl
autoreconf -i
./configure --prefix=$PWD/build \
--enable-all --enable-aesni --enable-harden --enable-keylog-export \
--disable-ech --enable-mlkem
make -j$(nproc)
make installThe BoringSSL route is the same shape with cmake instead of autotools, the aws-lc route adds -DDISABLE_GO=ON, and the LibreSSL route carries a workaround for an autogen.sh failure through the LIBRESSL_GIT_OPTIONS environment variable. Every route ends with make -j$(nproc) check, so the test suite runs as part of the build rather than as a separate step. There are also instructions for Mac users who installed libev through MacPorts, which need LIBEV_CFLAGS and LIBEV_LIBS appended to the configure step.
A public test server, and the Alt-Svc hint
There are public endpoints to try the implementation against, and the way they are set up teaches you something about how QUIC is meant to be deployed. The endpoints are https://nghttp2.org:4433, https://nghttp2.org:4434 which requires an address validation token, and https://nghttp2.org itself, which is powered by nghttpx. The last one sends an Alt-Svc header field to clients if it is accessed via HTTP/1.1 or HTTP/2, to tell them that HTTP/3 is available at UDP 443. That is the mechanism by which a client that has never heard of QUIC discovers it, and it is worth looking at a real deployment of it, because the mapping between the HTTPS port and the UDP port is a recurring operational question for anyone putting QUIC in front of an existing site. The second endpoint requiring an address validation token is a different lesson, since stateless address validation is what a server needs to protect itself from amplification attacks when it has not yet seen a client's address, and the server enforces it with the -V, --validate-addr flag.
Four executables, two protocols
After a successful build, the client and server executables are found under the examples directory and they talk HTTP/3. The client is invoked as examples/wsslclient [OPTIONS] <HOST> <PORT> [<URI>...], and the notable option is -d, --data=<PATH>, to read data from a path and send it to the peer. The server is examples/wsslserver [OPTIONS] <ADDR> <PORT> <PRIVATE_KEY_FILE> <CERTIFICATE_FILE>, with the notable option -V, --validate-addr to enforce stateless address validation. Alongside them are wsslhqclient and wsslhqserver, which speak the HQ protocol tailored for the quic-interop-runner, which is how a new QUIC implementation proves it interoperates with everyone else's. The presence of both pairs is a design point rather than duplication, because the same transport is exercised by two very different upper layers, a full HTTP/3 stack and a deliberately minimal one, and an implementation that passes both is more likely to be correct than one that only passes the easy case.
Fuzzing, interop and a steady release rhythm
The repository shows a project that treats correctness as a continuous activity. There is a.clusterfuzzlite/ directory, a fuzz/ directory and an interop/ directory, and the examples tree has a file named examplestest.cc. The build system is autotools based, with configure.ac, Makefile.am, a cmake/ directory and a CMakeLists.txt, so both build systems are supported, and there is a CMakeOptions.txt, a fmtgen.py for the generated code, a docker/ directory and a ci/ directory. The licence is MIT with the text in COPYING, and the repository carries an AUTHORS file, a SECURITY.md, a NEWS file and a ChangeLog, and a makerelease.sh script. The release cadence is fast and regular, with v1.23.0 on 2026-05-31, v1.24.0 on 2026-06-28 and v1.25.0 on 2026-07-26, and the last push was on 2026-10-11, which for a protocol implementation is the pace you would want, since a QUIC library tracks a moving set of specifications.
Editorial conclusion
ngtcp2 is the right codebase for a team that needs to embed QUIC in something that is not a browser or a CDN, because the library itself has no dependencies, the C API is the product, and the examples show how the pieces are meant to be wired together rather than hiding that behind a framework. It is the wrong project for someone who wants a QUIC server in an afternoon, because the TLS backend has to be chosen, built and configured by hand. Before you start, read the requirements section and pick a TLS backend from the list, since the build script differs for each and the versions are pinned to specific commits, and use the public test server at nghttp2.org:4433 to check that your build interoperates before you point it at anything of your own.
Frequently asked questions
What is ngtcp2?
It is a C implementation of the IETF QUIC protocol defined in RFC 9000, and the project describes itself as an effort to implement it. The libngtcp2 library has no external dependencies and needs a C11 compiler, while the example client and server are written in C++23.
Which TLS backends can ngtcp2 be built with?
At least one of quictls, which is deprecated, GnuTLS 3.7.5 or newer, BoringSSL at a pinned commit, aws-lc 1.39.0 or newer, Picotls at a pinned commit, wolfSSL 5.5.0 or newer, LibreSSL v3.9.2 or newer, or OpenSSL 3.5.0 or newer, which is marked experimental.
What do I need to build the ngtcp2 examples?
Besides a TLS backend, the examples need libev and nghttp3, the HTTP/3 implementation from the same organisation, and the BoringSSL and aws-lc examples additionally need libbrotli-dev 1.0.9 or newer for TLS certificate compression. Building from git also requires git submodule update --init.
How can I test an ngtcp2 build?
Against the public endpoints at https://nghttp2.org:4433, https://nghttp2.org:4434 which requires an address validation token, and https://nghttp2.org, which sends an Alt-Svc header over HTTP/1.1 or HTTP/2 to advertise HTTP/3 on UDP 443. Locally, the build ends with make check, and the wsslhqclient and wsslhqserver programs speak the HQ protocol used by the quic-interop-runner.
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/ngtcp2-ngtcp2)Was this useful?