Liking cljdoc? Tell your friends :D


Clojars Project

An HTTP/1.1, HTTP/2, HTTP/3 and WebSocket server for Clojure Ring handlers, with no dependency besides Clojure. The core is written in Java for Ring and runs on virtual threads.

Status: alpha. Option names and the API may still change between releases (see the changelog).

Installation

{:deps {com.s-exp/enso {:mvn/version "1.0.0-alphaN"}}}

HTTP/3 is optional. It needs a second artifact for your platform, which contains a JNI shim with libquiche linked in, so there is nothing to install on the system:

{:deps {com.s-exp/enso             {:mvn/version "1.0.0-alphaN"}
        com.s-exp/enso$linux-amd64 {:mvn/version "1.0.0-alphaN"}}}

Classifiers: linux-amd64, linux-arm64, linux-musl-amd64, linux-musl-arm64, darwin-arm64.

Quick start

(require '[s-exp.enso :as enso])

(def server
  (enso/run-server (fn [req] {:status 200 :body "hello"})
                   {:port 8080}))

(enso/stop server)

With TLS, HTTP/2 and HTTP/3:

(enso/run-server handler
  {:port 8443
   :ssl-context ssl-context ; a javax.net.ssl.SSLContext
   :http2 true
   :http3 true
   :http3-cert-path "cert.pem"
   :http3-key-path "key.pem"})

Features

  • HTTP/1.1 with keep-alive, pipelining, chunked bodies and trailers, Expect: 100-continue and zero-copy file bodies.
  • HTTP/2 over TLS, or cleartext with prior knowledge (:http2c).
  • HTTP/3 through Cloudflare's quiche, advertised with Alt-Svc, with certificate reloading.
  • WebSocket over HTTP/1.1, with optional permessage-deflate.
  • Ring sync and async handlers, the Ring 1.11 WebSocket API, StreamableResponseBody, and a streaming body for SSE and long-poll.
  • One virtual thread per connection (per stream on HTTP/2 and HTTP/3), with blocking I/O.
  • The same timeouts and limits on every protocol, and connection, request and error events through a callback map or JFR.

Conformance: h2spec 146/146 over TLS, Autobahn TestSuite 517/517, h3spec 75/77 (the two failures are checks inside libquiche).

Performance

On an M1 Pro laptop (8 CPUs, JDK 25), a 13-byte response, server and load generator sharing the cores:

req/sallocated per request
HTTP/1.1 GET124k393 B
HTTP/1.1 pipelined1.4M235 B
HTTP/2 GET over TLS745k1.1 KB
HTTP/3 GET73k801 B
WebSocket echo1.0M msg/s333 B

In a separate-process comparison with http-kit, Jetty, Aleph and Netty, enso has the highest throughput on every scenario above and allocates 393 bytes per HTTP/1.1 request where the others allocate 3.6 to 4 KB. doc/performance.md has latency percentiles, uploads, and the full comparison.

Requirements: JDK 21 or later and Clojure 1.12 or later. HTTP/3 runs on Linux (glibc 2.28+ or musl) and macOS 11+ on Apple Silicon, and on JDK 24+ needs --enable-native-access=ALL-UNNAMED.

Documentation

  • Options: every run-server option and its default.
  • Handlers: the request map, response bodies, streaming, async handlers, errors, WebSocket, and the supported API.
  • Deployment: production checklist, default limits, what the server protects against.
  • HTTP/3: setup, certificates, how the QUIC event loops work, native shim.
  • Performance: throughput, latency and allocation numbers, and how to reproduce them.
  • Architecture: how the server is built, for people working on it.
  • Testing: the test suite, fuzzing, conformance suites, benchmarks and CI.
  • HTTP/3 conformance: h3spec results.
  • Building: build tasks, jars, the native shim and releases.
  • Changelog
  • Security policy

Prior art

The TLS layer (SSLEngine over SocketChannel) follows the pattern used by Helidon Níma (Apache 2.0). Ensō implements it from scratch; no code was copied.

License

Copyright © 2026 Max Penet.

Distributed under the Mozilla Public License 2.0 (FAQ).

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close