A fast, modern C++20 HTTP/HTTPS server & routing framework
Express-style ergonomics on an epoll event loop with zero-copy file serving.
http · https · rest-api · middleware · sse ·
pulse · websocket · sessions · cors · rate-limit ·
gzip · static-files · sendfile · json · multipart ·
cookies · high-performance · zero-copy ·
web-framework · backend · cpp20 · cmake
#include <socketify/socketify.h>
using namespace socketify;
int main() {
Server server;
server.Get("/", [](Request&, Response& res) {
res.send("Hello, world!\n");
});
server.Get("/users/:id", [](Request& req, Response& res) {
res.json({{"id", req.params().at("id")}});
});
server.Listen(8080);
server.Wait();
}- HTTP/1.1 — keep-alive, pipelining, chunked transfer decoding,
Expect: 100-continue, configurable header/body limits and timeouts - HTTPS — TLS 1.2+ via OpenSSL, cert/key from files or environment, one code path for HTTP and HTTPS
- Routing —
:params,*wildcards, route groups, per-route and global middleware, automaticHEADfallback and 405 handling - Request/response — lazy query/cookie parsing, JSON body
(
nlohmann::json), urlencoded forms, multipart file uploads, streaming/chunked responses, redirects - Static files — zero-copy
sendfile(2), ETag/Last-Modified, Range requests, directory indexes, SPA fallthrough - Middleware built-ins — request logging (IP + status-aware levels), request IDs, CORS,
token-bucket rate limiting (
RateLimit-*headers), gzip/deflate compression, body-size limits - Sessions — pluggable manager: server store, signed cookie, or JWT
(cookie / Bearer); rolling TTL,
regenerate(), default MemoryStore - ORM / database —
socketify::dbmodels & schema DSL for SQLite, PostgreSQL, MySQL; MongoDB documents (memory://or mongo-cxx); migrations, validations, hooks, relations, pools, transactions - Server-Sent Events —
sse::upgrade()with a thread-safe session handle for pushing events from any thread - Pulse — bidirectional realtime channels (
pulse::upgrade/Channel/Hub); pulse_easy JSON events; pulse_media voice/video/image streaming; RFC 6455 WebSocket under the hood so browsers andwscatwork unchanged - JSON helpers —
socketify::json_utildotted-path access, safe parse,req.json()/res.json_error() - Validation —
socketify::validatedeclarative schemas for request bodies - Config —
socketify::configtyped env +.envfile loader - Cache —
socketify::cachethread-safe TTL key/value store with JSON helpers - HTTP client —
socketify::http_clientsynchronous GET/POST with optional TLS - Performance architecture — one epoll loop per worker thread,
SO_REUSEPORTlisteners (no accept contention), non-blocking sockets, buffered writes, timer-based connection expiry
Charts are animated SVGs (transparent background; labels adapt to light/dark themes). Click a section to expand or collapse.
HTTP /ping — Socketify vs Express / Flask / Django
Same machine, same endpoint, same load tool.
| What | GET /ping → {"ok":true} (no DB, no templates) |
| How | wrk -t4 -c100 -d8s, localhost keep-alive |
| Where | Intel i7-12700K · 20 threads · Linux · 2026-07-20 |
| Rank | Framework | req/s | vs Socketify |
|---|---|---|---|
| 1 | Socketify (C++20 · epoll) | 909,254 | — |
| 2 | Express 4 (Node.js) | 61,208 | ~15× slower |
| 3 | Flask 3 + Waitress | 1,862 | ~488× slower |
| 4 | Django 4 + Waitress | 1,202 | ~757× slower |
| Framework | avg | p50 | p99 |
|---|---|---|---|
| Socketify | 0.080 ms | 0.054 ms | 0.124 ms |
| Express | 1.98 ms | 1.57 ms | 2.30 ms |
| Django | 82.5 ms | 90.5 ms | 123 ms |
| Flask | 86.3 ms | 51.6 ms | 1140 ms |
Methodology & how to reproduce
Why Socketify wins this test: native C++20, epoll + SO_REUSEPORT workers, almost no per-request overhead. Interpreted stacks (Node / Python) pay runtime and middleware costs even on a trivial handler.
Public suites (different hardware — order only):
| Source | Express | Flask | Django |
|---|---|---|---|
| Sharkbench (2025-08) | ~5,766 | ~1,092 | ~950 |
Commodity /ping write-up |
~6,500 | — | much lower w/ default middleware |
Micro-benchmarks ≠ production apps (DB, auth, business logic dominate there). Always measure your workload. Raw JSON:
benchmarks/results.json.
./benchmarks/run_all.sh
# optional: DURATION=10 CONCURRENCY=200 ./benchmarks/run_all.shPulse (WebSocket) — why Pulse, echo & Hub fan-out
Pulse is RFC 6455 WebSocket on the wire (ws:// / wss://). Browsers, wscat,
and Node clients work unchanged. You pick Pulse when you want that protocol plus
Socketify Hub rooms, pulse_easy JSON events, pulse_media voice/video/image
streaming, and the same C++ epoll server as your HTTP API — one process, one binary.
| Raw WebSocket DIY | Pulse | |
|---|---|---|
Browser / wscat compatible |
✅ | ✅ |
| Rooms + broadcast | you write it | pulse::Hub built-in |
| JSON event API | you write it | pulse_easy |
| Voice / video / image frames | you write it | pulse_media |
| Encode-once fan-out | usually re-encode per peer | broadcast_frame (~5.7× faster) |
| Same stack as HTTP/HTTPS | often separate | one Server |
128 concurrent clients · 64-byte text echo · asyncio load client · 8s
| Rank | Stack | msg/s | vs Pulse |
|---|---|---|---|
| 1 | ws (Node.js) | 80,122 | ~1.05× Pulse |
| 2 | Pulse (Socketify) | 76,600 | — |
| 3 | websockets (Python) | 63,511 | ~1.2× slower |
| Stack | avg | p50 | p99 |
|---|---|---|---|
Node ws |
1.59 ms | 1.58 ms | 1.75 ms |
| Pulse | 1.67 ms | 1.66 ms | 1.85 ms |
Python websockets |
2.01 ms | 1.99 ms | 2.58 ms |
Echo is client-bound here (asyncio load gen) — Pulse sits in the same ballpark as
Node ws and ahead of Python. The bigger win is Hub fan-out and the batteries above.
1,000 peers · 256 B · broadcast_frame vs N× send_text re-encode
| Approach | delivered msg/s | vs encode-once |
|---|---|---|
Hub broadcast_frame (encode-once) |
38,554,933 | — |
Naive per-peer send_text |
6,802,453 | ~5.7× slower |
How to reproduce
./benchmarks/run_pulse.sh
# optional: DURATION=8 CLIENTS=128 ./benchmarks/run_pulse.sh
# Hub microbench: ./benchmarks/servers/pulse_hub_fanout 1000 2000Raw numbers: pulse_results.csv ·
pulse_hub_results.csv
| Dependency | Notes |
|---|---|
| Linux | epoll / sendfile / SO_REUSEPORT |
| C++20 compiler | GCC 12+ or Clang 15+ |
| CMake | ≥ 3.16 |
| nlohmann_json | ≥ 3.11 |
| ZLIB | gzip / deflate |
| OpenSSL 1.1.1+ | optional; only when SOCKETIFY_WITH_TLS=ON (default) |
# Debian / Ubuntu
sudo apt install build-essential cmake ninja-build \
nlohmann-json3-dev zlib1g-dev libssl-devRipple and other showcase apps live as git submodules under examples/.
Clone with recursion so they come along:
git clone --recurse-submodules https://github.com/MSaLeHNYM/Socketify.git
cd SocketifyAlready cloned without submodules?
git submodule update --init --recursivecmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
-DSOCKETIFY_BUILD_EXAMPLES=ON
cmake --build build -j$(nproc)Or use the helper script:
./scripts/build_release.sh./scripts/build_debug.sh
# equivalent to:
# cmake -S . -B build-debug -DCMAKE_BUILD_TYPE=Debug \
# -DSOCKETIFY_BUILD_TESTS=ON \
# -DSOCKETIFY_SANITIZE=address,undefined
# cmake --build build-debug -j$(nproc)
# ctest --test-dir build-debug --output-on-failurecmake --install build --prefix /usr/local
# then in your app:
# find_package(Socketify 0.2 REQUIRED)
# target_link_libraries(app PRIVATE Socketify::socketify)
socketify --version
socketify --run-http ./public --port 8080Version is read from the root VERSION file (see docs/VERSIONING.md).
Bump with ./scripts/bump-version.sh patch|minor|major.
| Option | Default | Meaning |
|---|---|---|
SOCKETIFY_WITH_TLS |
ON |
HTTPS support (needs OpenSSL) |
SOCKETIFY_WITH_SQLITE |
ON |
SQLite driver for socketify::db |
SOCKETIFY_WITH_POSTGRES |
OFF |
PostgreSQL driver (libpq) |
SOCKETIFY_WITH_MYSQL |
OFF |
MySQL driver (libmysqlclient) |
SOCKETIFY_WITH_MONGO |
OFF |
MongoDB driver (mongo-cxx); memory:// always available |
SOCKETIFY_BUILD_CLI |
ON (top-level) |
Build/install the socketify manager binary |
SOCKETIFY_BUILD_EXAMPLES |
OFF |
Build examples/ |
SOCKETIFY_BUILD_TESTS |
OFF |
Build GoogleTest suite |
SOCKETIFY_BUILD_DOCS |
OFF |
Add a docs Doxygen target |
SOCKETIFY_SANITIZE |
(empty) | e.g. address,undefined |
SOCKETIFY_WERROR |
OFF |
Treat warnings as errors |
Convenience scripts:
| Script | What it does |
|---|---|
scripts/build_release.sh |
Optimized Release build (+ examples) |
scripts/build_debug.sh |
Debug + ASan/UBSan + tests |
scripts/run_tests.sh |
Build (if needed) and run CTest |
scripts/run_examples.sh [01-07] |
Build & run one graded example |
scripts/serve_docs.sh [port] |
Generate Doxygen docs, serve on localhost, open browser |
scripts/bump-version.sh |
Bump SemVer in VERSION (patch/minor/major) |
After cmake --install build:
find_package(Socketify 0.2 REQUIRED)
# Socketify_VERSION is set (e.g. "0.2.2")
target_link_libraries(app PRIVATE Socketify::socketify)#include <socketify/version.h>
// SOCKETIFY_VERSION_STRING / socketify::version_string()Or add Socketify as a subdirectory / FetchContent and link Socketify::socketify.
| Example | Shows |
|---|---|
01_hello_world |
routes, path params, JSON |
02_rest_api |
CRUD API, groups, body parsing, status codes |
03_middleware |
logging, CORS, rate limit, sessions, custom auth |
04_static_site |
static files, compression, SPA fallback |
05_sse_chat |
live feed over Server-Sent Events |
06_https |
TLS with a self-signed dev cert |
07_fullstack |
everything combined: frontend + API + sessions + SSE |
08_nexus_board |
React + SQLite app: auth, projects, kanban, uploads, live SSE |
09_orm_demo |
socketify::db ORM: models, relations, migrations, Mongo documents |
10_pulse_chat |
lobby chat over Pulse (browser WebSocket + pulse::Hub) |
11_pulse_media |
Pulse Easy + voice/image relay via pulse_media |
ripple |
Ripple — Telegram-style messenger (Pulse + SQLite + React) · submodule |
Ripple — Messages that ripple.
Full messenger showcase: accounts, DMs, groups, presence, typing indicators.
Built with Socketify Pulse + db ORM (SQLite) + React · MIT licensed.
./scripts/run_examples.sh 07 # fullstack guestbook
./scripts/run_examples.sh 10 # Pulse lobby chat
./scripts/run_examples.sh ripple # Ripple messenger → http://localhost:8080203 unit and integration tests (GoogleTest), run under AddressSanitizer/UBSan in the debug build:
./scripts/run_tests.sh- Hand-written guide: docs/API.md
- API reference (local only) — generate with the script; HTML is written
to
docs/generated/which is gitignored (not pushed to GitHub):
./scripts/serve_docs.sh # regen + http://127.0.0.1:8765/
./scripts/serve_docs.sh 9000 # custom port
./scripts/serve_docs.sh --regen-onlyRequires doxygen on PATH (or under .deps/sysroot/usr/bin/doxygen).
- Pulse permessage-deflate (optional compression extension)
- HTTP/2 (ALPN, h2c)
- Pluggable auth helpers (JWT, HMAC)
- Redis-backed session/rate-limit stores
- OpenTelemetry exporter
Copyright © 2025–2026 M SaLeH NYM. All rights reserved.
Socketify is released under a source-available license (see LICENSE):
| You may | You may not (without written permission) |
|---|---|
| Use Socketify as a library to build & ship your own apps | Modify / fork / redistribute changed copies of Socketify |
| Link statically or dynamically against an unmodified build | Treat Socketify as open-source-to-relicense |
Want to contribute a patch? Ask first — email saleh.ue4@gmail.com or Telegram t.me/MSaLeHNYM for permission. Approved contributions are assigned to the copyright holder so ownership stays unified.
All copyright and legal ownership of this software belong exclusively to M SaLeH NYM.
