# httpserver.h: a single header C library for event driven HTTP servers

> httpserver.h is a one file C library that builds non-blocking, event driven HTTP servers on epoll for Linux and kqueue for the BSDs and macOS, with the entire API documented in the header itself. The repository also carries a unit, functional and C++ test rig, a clang-format setup, an include-what-you-use mapping and a fuzz target, and a benchmark against nginx that the author is careful to frame as a reference point rather than a claim.

**jeremycw/httpserver.h** — Single header library for writing non-blocking HTTP servers in C

- Repository: https://github.com/jeremycw/httpserver.h
- Stars: 1,946 · Forks: 158
- Language: C
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/jeremycw-httpserver-h

## One header, two event loop backends, and the docs are in the file

httpserver.h is described as a single header C library for building event driven, non-blocking HTTP servers, and it supports Linux with epoll and BSD and Mac with kqueue. The single header design is the whole packaging story. There is no library to link, no configure step and no dependency, and the implementation is compiled into your translation unit by defining a macro before the include, so the compiler sees the code and can inline it. The API documentation lives in the header itself, which the README points at with the note to see `httpserver.h` for API documentation, and the repository carries a Doxyfile for generating the reference from it. The surrounding tree is small and conventional: a `CMakeLists.txt`, a `Makefile`, a `src/` directory, a `test/` directory, a `compile_commands.json` for tooling, an `iwyu.imp` file that is an include-what-you-use mapping, and a `state_diagram.uml` that documents the server's state machine. For a library whose whole point is to be readable in one sitting, that layout is consistent: there is nowhere for the real documentation to hide.

## The API is a response object and a callback

The example in the README shows the shape of the whole library, and it is short enough to memorise. You define a handler that takes a request pointer and returns nothing, build a response with `http_response_init()`, set a status code, add a header, set the body, and hand it back with `http_respond()`. The server is then created with `http_server_init()` on a port and the handler, and started with `http_server_listen()`:

```c
#define HTTPSERVER_IMPL
#include "httpserver.h"

#define RESPONSE "Hello, World!"

void handle_request(struct http_request_s* request) {
  struct http_response_s* response = http_response_init();
  http_response_status(response, 200);
  http_response_header(response, "Content-Type", "text/plain");
  http_response_body(response, RESPONSE, sizeof(RESPONSE) - 1);
  http_respond(request, response);
}
```

Two design choices are visible in those lines. The response is a separate object that you fill in and then hand over, so the library controls when and how it is written to the socket, and the body takes an explicit length, with `sizeof(RESPONSE) - 1` to drop the terminating null, which means binary payloads work as well as text. The handler is called with the request and returns nothing, so the response path is always explicit, and the event loop stays inside the library. A user who wants to know what else is available reads the header, because that is where the full set of functions and the state diagram are described.

## The nginx benchmark, read with care

The README publishes a benchmark against nginx and, importantly, states its purpose before showing any number: the author ran some micro-benchmarks with httpserver.h and NGINX serving a simple Hello, World, and the purpose was just to get a performance reference point, not to try and make any statement of superiority, since httpserver.h is not a competitor or replacement for NGINX. The measurements use ApacheBench with 200 concurrent connections and 100,000 requests. With keep-alive, nginx 1.14.0 is reported at 74,441.26 requests per second against 123,907.91 for httpserver.h, and with `Connection: close` the figures are 15,773.47 against 27,605.45. The nginx configuration is included, and it is a single worker process returning a fixed 200 response, so the comparison is between a minimal static responder and a minimal dynamic server rather than between two servers doing the same work. The connection time statistics are the more interesting part of the table, since the nginx runs show a long tail with a maximum connect time of 1,029 and 1,123 milliseconds against a maximum of 4 and 6 milliseconds for httpserver.h. Read the numbers as what they are, a Hello World reference point on one machine.

## The test rig is more mature than the README suggests

The Makefile is where the engineering discipline shows. The `test` target runs three suites, a unit test runner built under the debug directory, a functional test runner, and the same functional runner in its C++ mode, which is a good sign that the library is usable from C++ as well as C. The `debug` target is not a plain build, since it configures CMake with `CMAKE_BUILD_TYPE=Debug` and passes the include-what-you-use settings, including the mapping file in the repository, then runs make, so every local test run also checks that the headers are included properly. There is a `format` target that runs clang-format with the LLVM style over the sources, a `check-format` target that runs the same tool in dry-run mode with warnings as errors, and a `clean` target. The `fuzz` target is the most interesting, because it compiles the fuzz harness at `test/fuzz/random_parser.c` with clang at `-g -O0` and the `KQUEUE` define, links it against the built static library `libhttpsrv.a`, and runs it with a seed passed on the command line. For a library that parses bytes off a socket, having a seeded random parser fuzz target wired into the build is the part of the repository that most reduces the risk of shipping it.

## What this library is not, and the boundary to keep in mind

The honest limitation is stated in the README itself, that httpserver.h is not a competitor or replacement for nginx, and the benchmark reinforces it. nginx is a full production web server with its own configuration file, and nothing in this repository claims to be in that class. The scope here is a small, readable HTTP server for a program that wants to speak HTTP without dragging in a stack, and the trade is explicit: you get one header and complete visibility into the behaviour, and in exchange you own the details. The README documents none of the production concerns, so there is no mention of TLS, of HTTP/2, of a configuration file, of access logging or of graceful shutdown, and a reader should not assume those exist. The single header also means the implementation is compiled into every translation unit that includes it, which is fine for a small service and is a real cost for a large one.

## Maintenance and the state of the tree

The repository is MIT licensed, with the LICENSE file at the root, and it carries a Travis CI badge for the master branch along with a `.github/` directory. There are no GitHub releases, so there is no version to pin and no changelog to read, which for a single header library is a reasonable arrangement since copying the file is the entire installation step, but it does mean the master branch is the only reference point. The last push was on 2026-04-26. The interesting maintenance signal is in the tooling rather than in the commits, since the presence of the format check, the include-what-you-use mapping and the fuzz target indicates a project that keeps its own house in order. For anyone embedding this, the sensible routine is to take the header, keep the `HTTPSERVER_IMPL` include in exactly one translation unit, run the project's own test suite against your fork, and re-run the format check, because those three steps are what the maintainer runs and they are cheap.

## Conclusion

Adopt httpserver.h if you are writing a C or C++ service that needs an HTTP server without a dependency tree, you understand event loops well enough to own the behaviour, and you want to read the whole API in one file. Do not adopt it to replace nginx, since the README says plainly that the project is not a competitor or replacement for nginx, and the benchmark is a Hello World comparison rather than a serving benchmark. Before you build, run the test targets and the format check so your fork matches the project's clang-format style, and read the header rather than the README, because that is where the API documentation lives. The licence is MIT, the repository publishes no GitHub releases, and the last push was on 2026-04-26.

## FAQ

### How do I use httpserver.h in a C program?

Define `HTTPSERVER_IMPL` before including the header so the implementation is compiled into your program, write a handler that builds a response with `http_response_init()`, `http_response_status()`, `http_response_header()` and `http_response_body()`, send it with `http_respond()`, then create the server with `http_server_init()` and start it with `http_server_listen()`.

### Which operating systems does httpserver.h support?

The README states that it supports Linux with epoll and BSD and Mac with kqueue. The build system also carries a `KQUEUE` define, used among other things when compiling the fuzz harness.

### Is httpserver.h a replacement for nginx?

No, and the README says so explicitly, describing the benchmark as a performance reference point rather than a claim of superiority, and noting that httpserver.h is not a competitor or replacement for NGINX. The published numbers come from a Hello World response with 200 concurrent connections and 100,000 requests.

### How do I build and test httpserver.h?

The Makefile has a `build` target that creates the build directory, a `debug` target that configures CMake in Debug mode with include-what-you-use settings and runs make, and a `test` target that runs the unit runner, the functional runner and the functional runner in C++ mode. There are also `format` and `check-format` targets using clang-format, and a `fuzz` target.

## Sources

- [Issues](https://github.com/jeremycw/httpserver.h/issues)
- [jeremycw/httpserver.h on GitHub](https://github.com/jeremycw/httpserver.h)
- [License: MIT](https://github.com/jeremycw/httpserver.h/blob/master/LICENSE)
- [README](https://github.com/jeremycw/httpserver.h/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/jeremycw-httpserver-h
