1 minute read

Jetty is an open-source Java-based HTTP server and servlet container. It’s what actually listens on a port, accepts incoming HTTP requests, and hands them off to your application.


In the context of Clojure/Ring:

Since Clojure runs on the JVM, it can use Java libraries directly. Ring provides an adapter called ring-jetty-adapter that bridges your Clojure handler functions with Jetty’s Java internals. So the flow looks like:

Browser request
      ↓
   Jetty (Java HTTP server — listens on port 3000)
      ↓
 ring-jetty-adapter (translates Java HTTP → Clojure map)
      ↓
  Your Ring handler (just a Clojure function)
      ↓
 ring-jetty-adapter (translates Clojure map → Java HTTP response)
      ↓
   Jetty (sends response back to browser)

Why Jetty specifically?

It’s the default in the Ring/Compojure ecosystem because it’s:

  • Embeddable — runs inside your app’s process, no separate server install needed
  • Lightweight — starts fast, low overhead for development
  • Battle-tested — used in production by many large projects (Eclipse IDE, Hadoop, etc.)

Starting it in your Compojure project:

;; In your handler.clj or core.clj
(use 'ring.adapter.jetty)

(run-jetty app {:port 3000})

Or just via Leiningen:

lein ring server

This spins up Jetty on port 3000 and serves your Compojure routes.


Alternatives to Jetty in the Clojure world:

Server Library
Jetty ring-jetty-adapter
HTTP Kit http-kit
Undertow ring-undertow-adapter
Netty aleph

They’re all interchangeable from Ring’s perspective — your handler code stays the same regardless of which server sits underneath.

Updated: