Automatic Code Reloading
Ring Framework
Jetty Server
Software Development
Code Deployment

Automatic Code reloading in Ring / Jetty

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Ring and Jetty development, automatic code reloading is usually a development convenience built around namespace reloading rather than a magical property of Jetty itself. The common approaches are Ring development middleware for request-time reloading or tools.namespace driven reloads from the REPL.

Jetty serves requests, but Clojure reloading is the real mechanism

Jetty is the HTTP server. Ring is the handler abstraction. Automatic reloading comes from the Clojure side, where changed namespaces are reloaded into the running process.

That distinction matters because the right setup is usually:

  • Jetty for serving
  • Ring middleware or REPL tooling for reload behavior

Not "Jetty does hot reload by itself."

Request-time reload middleware is the simple option

For development, ring.middleware.reload is a straightforward pattern:

clojure
1(ns my-app.dev
2  (:require [ring.adapter.jetty :refer [run-jetty]]
3            [ring.middleware.reload :refer [wrap-reload]]
4            [my-app.core :refer [app]]))
5
6(defn -main []
7  (run-jetty (wrap-reload #'app)
8             {:port 3000 :join? false}))

Here, wrap-reload checks changed namespaces and reloads them during development requests. It is convenient because it keeps the feedback loop short without requiring a full server restart for ordinary source edits.

tools.namespace gives more explicit control

A more robust REPL-driven workflow uses clojure.tools.namespace.repl:

clojure
1(ns user
2  (:require [clojure.tools.namespace.repl :refer [refresh]]))
3
4;; At the REPL
5(refresh)

This approach is especially popular when you want controlled reload boundaries rather than request-triggered behavior. Many experienced Clojure developers prefer it because it is explicit and integrates well with interactive development.

Use the right tool for development only

Automatic code reloading is for development, not production. In production you usually want:

  • immutable deploy artifacts
  • explicit startup lifecycle
  • predictable state initialization

Request-time reload checks or namespace-refresh loops are useful during iteration, but they are not a deployment strategy.

Stateful components need extra care

Code reloading is easiest when handlers are mostly pure and state is externalized. If the application holds stateful components such as:

  • database pools
  • background jobs
  • caches
  • long-lived atoms with implicit lifecycle

then reload behavior can become messy unless the system is designed to stop and restart components cleanly.

This is why Clojure development workflows often pair reloading with lifecycle tools such as Integrant, Component, or Mount-style patterns.

Keep the development feedback loop tight

A common productive setup is:

  • Jetty running in-process
  • Ring handler wrapped with reload middleware or REPL refresh flow
  • an editor connected to the REPL

That gives quick iteration without restarting the JVM for every handler change.

Middleware reload and REPL reload can coexist

Many teams use lightweight request-time reload during early development and fall back to explicit REPL refresh when the application lifecycle becomes more complex. The two approaches are complementary rather than mutually exclusive. That flexibility is one reason the Clojure development experience stays productive even as applications grow.

Common Pitfalls

  • Assuming Jetty alone provides code reloading.
  • Using reload-oriented middleware in production.
  • Relying on automatic reload while ignoring application state and lifecycle issues.
  • Expecting every code change, including low-level startup code, to reload cleanly.
  • Skipping REPL-based workflows even though they are often the most reliable Clojure development path.

Summary

  • Automatic reloading in Ring and Jetty is mainly a Clojure namespace-reloading feature, not a Jetty feature.
  • 'wrap-reload is a simple development-time middleware solution.'
  • 'tools.namespace offers a more explicit and often more robust REPL-driven workflow.'
  • Reloading works best when application state is managed cleanly.
  • Use these techniques for development speed, not for production serving.

Course illustration
Course illustration

All Rights Reserved.