1 Overview and history

1.1 Origins and development

Hunchentoot was created by Edi Weitz in the early 2000s as a response to the lack of a robust, pure‑Common‑Lisp web server. Prior to Hunchentoot, Lisp web development relied on external servers or simple socket‑based implementations. Weitz aimed to produce a full HTTP/1.1 compliant server that could be used both for development and production. The project was first publicly released in 2006 under a permissive open‑source license, and it quickly gained traction within the Common Lisp community for its simplicity and performance.

1.2 Release history

Hunchentoot has undergone several major revisions. Version 1.0 introduced the core HTTP/1.1 support and basic file serving. Version 1.1 added HTTPS via integration with Common Lisp’s cl+ssl library. Version 1.2 improved session management and introduced cookie‑based sessions. Subsequent releases (1.3, 1.4, 2.0) refined threading, added a flexible dispatch system, and provided better integration with modern Lisp web frameworks. The most recent stable release is version 2.0 (as of 2025), which includes support for HTTP/2 via a plugin and improved concurrency models.

2 Core features

2.1 HTTP/1.1 and HTTPS support

Hunchentoot implements the HTTP/1.1 protocol as defined in RFC 2616, including persistent connections, chunked transfer encoding, and conditional requests. HTTPS support is enabled through the Common Lisp library cl+ssl, allowing encrypted connections using TLS. Users can configure SSL certificates and cipher suites, making Hunchentoot suitable for secure web applications.

2.2 Session management

Hunchentoot provides a built‑in session management system that associates state with client connections across requests. Sessions can be configured to expire after a configurable idle time, and their data is stored in an in‑memory hash table by default.

The default session tracking mechanism uses HTTP cookies. On the first request, Hunchentoot sets a session cookie; subsequent requests from the same client are automatically associated with that session. Developers can access session variables using a straightforward API.

2.2.2 Session storage backends

While the default storage is in‑memory, Hunchentoot allows custom session storage backends. Third‑party libraries provide persistent storage (e.g., hunchentoot-session-store for MySQL or SQLite), enabling session data to survive server restarts and scale across multiple instances.

2.3 Request handling

Hunchentoot processes incoming HTTP requests through a hierarchical dispatch system. Each request is matched against a list of handlers, and the first matching handler processes it.

2.3.1 Dispatch mechanisms

The primary dispatch mechanism is the *acceptor*, which listens for connections and hands each request to the dispatch table. Users can modify the dispatch table to add custom handlers, or they can define *easy handlers*—functions that are directly registered with a URI pattern. Additionally, Hunchentoot supports *dispatch macros* that allow advanced pattern matching on request paths.

2.3.2 Default dispatch table

The default dispatch table includes handlers for serving static files, retrieving session information, and handling errors. Users can extend or override this table. The default order of dispatch is: file serving (if enabled), then session handlers, then user‑defined handlers.

2.4 File serving and MIME types

Hunchentoot can serve static files from a specified document root. It automatically determines the MIME type of files based on their extension using a built‑in MIME type table. Developers can customize this table or disable file serving entirely. The file handler supports directory listing, range requests, and caching headers.

2.5 Threading and concurrency

Hunchentoot supports multiple threading models. In its default mode, it uses a single‑threaded event loop for I/O, processing requests sequentially. For concurrent environments, it can be configured to use a thread pool: each request is handled by a separate thread, allowing simultaneous processing. The choice between single‑threaded and multi‑threaded modes depends on the application’s concurrency requirements.

3 Architecture

3.1 Event loop and acceptor

The core of Hunchentoot is an *acceptor* object that listens on a TCP port (or Unix socket). The acceptor runs an event loop that accepts incoming connections, reads HTTP requests, and dispatches them. In single‑threaded mode, the same thread processes all requests; in multi‑threaded mode, a task queue handles parallel execution.

3.2 Request and response objects

Each HTTP request is represented by a request object, containing fields such as uri, method, parameters, cookies, and headers. Responses are built using a response object, which stores status codes, headers, and the response body. Hunchentoot provides convenience functions for modifying these objects (e.g., set-return-code, redirect).

3.3 Handler hierarchy

Handlers are functions that accept a request and produce a response. They are registered in the acceptor’s dispatch table.

3.3.1 User‑defined handlers

Developers can define handlers using the define-easy-handler macro, which automatically parses request parameters and binds them to function arguments. These handlers can also specify URI patterns, default arguments, and access to session data. Custom dispatchers (e.g., regex‑based) can be written by subclassing the dispatcher class.

3.3.2 Built‑in handlers

Hunchentoot includes several built‑in handlers: a file handler for static assets, a session handler for managing cookie‑based sessions, and an error handler for displaying backtraces (in development mode) or custom error pages. The hunchensocket extension provides WebSocket support as a specialized handler.

4 Usage and configuration

4.1 Basic setup

Hunchentoot is distributed via Quicklisp and can be loaded with (ql:quickload :hunchentoot). A minimal web server can be started with a single function call.

4.1.1 Starting and stopping the server

To start a server on port 8080: (start (make-instance 'hunchentoot:easy-acceptor :port 8080)). The server runs in the background and can be stopped with (stop *). Acceptor instances can be configured with parameters such as :name, :address, and :taskmaster.

4.1.2 Configuring ports and SSL

For HTTPS, create an acceptor of type hunchentoot:ssl-acceptor and pass :ssl-keyfile and :ssl-certfile arguments. Example: (make-instance 'hunchentoot:ssl-acceptor :port 443 :ssl-keyfile #P"key.pem" :ssl-certfile #P"cert.pem"). The cl+ssl library must be loaded beforehand.

4.2 Integration with web frameworks

4.2.1 Common Lisp web toolkits (e.g., Caveman, Weblocks)

Hunchentoot serves as the underlying HTTP engine for several Common Lisp web frameworks. Caveman (part of the Clack ecosystem) uses Hunchentoot as one of its supported backends. Weblocks, a widget‑based framework, also relies on Hunchentoot for request handling. Integration typically involves configuring the framework to use a Hunchentoot acceptor.

4.2.2 RESTful API development

Developers can build RESTful APIs by defining easy handlers that parse JSON or XML and return appropriate HTTP status codes. Hunchentoot’s built‑in parameter handling supports query parameters, POST data, and JSON payloads (via libraries like jonathan). URL routing is often handled with custom dispatchers or regex patterns.

4.3 Debugging and logging

4.3.1 Error handling and backtraces

By default, Hunchentoot catches unhandled errors during request processing and returns a 500 error page. In development mode (:show-lisp-errors-p t), it displays a full Lisp backtrace. Developers can customize error handling by overriding the handle-request method or by adding an error handler in the dispatch table.

4.3.2 Access logs

Hunchentoot can log HTTP requests to a file in Common Log Format (CLF) or Combined Log Format. Logging is enabled via the :access-log-destination acceptor parameter, which can be a filename, a stream, or :standard-output. The log includes the client IP, timestamp, method, URI, status code, and response size.

5 Extensions and community

5.1 Third‑party libraries

Several community libraries extend Hunchentoot’s functionality. Notable examples include:

  • hunchentoot-errors: Provides enhanced error page templates.
  • hunchentoot-auth: Implements basic HTTP authentication.
  • hunchentoot-websocket: Adds WebSocket support (via the hunchensocket package).
  • hunchentoot-session-mysql: Persistent session storage using MySQL.
  • restas: A routing library that integrates with Hunchentoot to simplify RESTful API development.

5.2 Documentation and tutorials

The official Hunchentoot manual is available on the project’s website, covering installation, API reference, and advanced configuration. Community tutorials exist on topics such as “Building a blog with Hunchentoot” and “Deploying Hunchentoot behind Nginx”. The Quickdocs system provides auto‑generated documentation for the latest release.

5.3 Performance benchmarks

Hunchentoot’s performance is generally adequate for moderate‑traffic web applications. Benchmarks from 2020 show that, on a single core, it can handle 3,000–5,000 requests per second for simple dynamic responses (in single‑threaded mode). Multi‑threaded mode scales well with the number of CPU cores. Compared to other Common Lisp web servers (e.g., Woo), Hunchentoot is often slightly slower due to its extra features, but it remains a reliable choice for production environments where ease of use and flexibility are prioritized.