velociradix
v5.0.5
Published
Zero-dependency, pure C++17 HTTP engine — event-driven (kqueue/epoll), trie router, middleware, SSE, CORS, static files. ~3.5x faster than node:http.
Maintainers
Readme
⚡ Velociradix
A zero-dependency, pure C++17 HTTP engine. Event-driven (kqueue/epoll) with
SO_REUSEPORT worker processes-threads, a trie router, middleware, route groups,
dynamic params, static files, CORS, and Server-Sent Events — no Node.js involved.
Benchmark (Apple M1, macOS): ~450k req/s native (64 conns × pipeline 64), 3.5x faster than
node:httpmeasured with the identical client.
✨ Features
- Event-driven core:
kqueueon macOS,epollon Linux, one worker thread per core. - Zero copy-ish I/O: pipelining, keep-alive, buffered reads,
send()withMSG_NOSIGNAL. - Trie router: fast literal + dynamic
:parammatching. - Middleware chain: global and per-route,
next()based. - Route groups: prefix groups (
/api/v1) with inherited middlewares. - CORS:
enable_cors()with built-in OPTIONS preflight. - Static files: safe directory serving (path-traversal protected).
- SSE:
ctx.sse(producer)with cross-thread streaming. - Zero dependencies: the whole engine is
velociradix.hpp+velociradix.cpp.
📦 Build
make # builds bin/velociradix_server + bin/velociradix.node
make test # runs the 22-test raw-socket suite
make bench # compares the JS addon path vs node:http (500k requests)
make cleanRequires clang++ / g++ with C++17, on macOS or Linux.
🚀 Quick Start
#include "velociradix.hpp"
using namespace velociradix;
int main() {
App app;
app.get("/", [](Context& ctx) {
ctx.send("Hello from velociradix!");
});
app.get("/users/:id", [](Context& ctx) {
ctx.json(json::object({
{"id", json::string(ctx.params["id"])},
}));
});
app.listen(8080, "0.0.0.0"); // blocks until app.close() is called
}Run:
./bin/velociradix_server [port] [host] [workers]🛠️ API
Routing
app.get("/path", handler);
app.post("/path", handler);
app.put("/path", handler);
app.del("/path", handler);
app.use(middleware); // global middleware
app.enable_cors(); // CORS headers + OPTIONS preflight
app.set_workers(8); // event-loop threads (default: all cores)
app.set_static_dir("./public");Route Groups
app.group("/api", [](RouteGroup& api) {
api.group("/v1", [](RouteGroup& v1) {
v1.get("/ping", [](Context& ctx) {
ctx.json(json::object({{"pong", "true"}}));
});
});
});Middleware
app.use([](Context& ctx, const std::function<void()>& next) {
ctx.set_header("x-engine", "velociradix");
next();
});Context (ctx)
| Member | Description |
| :--- | :--- |
| req | The parsed request (method, path, query_string, body, headers) |
| res | The response (status, body, headers) |
| params | Dynamic route params map |
| query("key") | Query string value |
| cookie("key") | Cookie value |
| status(code) | Set response status (chainable) |
| send(text) / json(raw) / html(body) | Respond |
| redirect(url, code=302) | Redirect |
| set_header(name, value) / set_cookie(name, value, attrs) | Headers & cookies |
| sse(producer) | Open a Server-Sent Events channel |
| serve_file(path) | Serve a file from disk |
Server-Sent Events (SSE)
app.get("/live", [](Context& ctx) {
ctx.sse([](SseStream& stream) {
std::thread t([&stream]() {
for (int i = 0; i < 5; ++i) {
stream.send_event(json::object({{"tick", json::number(i)}}), "update");
std::this_thread::sleep_for(std::chrono::seconds(1));
}
stream.close();
});
t.detach();
});
});Lifecycle
app.listen(port, host); // blocks the calling thread
app.close(); // wakes all loops; listen() returns (call from another thread)📊 Benchmark
The current benchmark (make bench) exercises the full JS path —
index.mjs facade → native addon → C++ engine — against node:http,
500,000 requests over 16 keep-alive connections with a 16-deep pipeline,
using the identical Node.js client for both servers:
velociradix (addon) : 500.0k requests in 3788ms -> 132.0k req/s
node:http : 500.0k requests in 5947ms -> 84.1k req/s
speedup vs node:http : 1.6xThe pure C++ engine alone (no JS bridge) reaches ~450k req/s.
📄 License
Distributed under the MIT License. See LICENSE for more information.
