Skip to content


Repository files navigation


Support library for Clojure servers built on the system/component pattern and Ring.

See example project templates:

Provides plumbing:

  • a place to store the system singleton, safe from namespace reloads (see below)
  • shortcuts for system lifecycle management: recreate, restart

Provides a smooth development experience:

  • automatic code reload on change
  • automatic system reset on code change
  • automatic webpage refresh on system reset
  • rendering of compile errors and runtime exceptions

Inspired by:

  • component.repl: system storage, lifecycle shortcuts
  • lein-ring: automatic code reload, webpage refresh, error rendering

Uses for code reload. Adapts it to work in background threads such as filesystem watchers. Properly refreshes namespaces in nREPL sessions (assumes

Comparison with component.repl:

  • automatic code reload

  • background code reload correctly refreshes the REPL

  • integrated webserver goodies: auto refresh on system reset, error rendering

Comparison with lein-ring:

  • not Ring-specific

  • doesn't mess with your build, AOT compilation works properly

  • code reload uses, avoiding limbo states

  • code reload involves a system reset, making it easy to redefine background activities such as job queues

  • background code reload correctly refreshes the REPL

  • code reload works on its own, you don't need a webpage open

  • code reload is vastly more reliable

  • page refresh is vastly more reliable


Add to project.clj:

[com.mitranim/forge "0.1.0"]

Require in code:

(:require [com.mitranim.forge :as forge])


(ns core
    [com.mitranim.forge :as forge]
    [com.stuartsierra.component :as component]))

(defn create-system [prev-system]
    (start [this] (println "starting") this)
    (stop [this] (println "stopping") this)))

(defn -main []
  (forge/reset-system! create-system))

(defn -main-dev []
  (forge/start-development! {:system-symbol `create-system})
  (forge/reset-system! create-system))

When using Ring, add the middleware that automatically refreshes webpages and renders errors:

(let [my-ring-handler (forge/wrap-development-features my-ring-handler)])

Launch your REPL and run an equivalent of this:

(forge/start-development! {:system-symbol `create-system})
(forge/reset-system! create-system)

Now, modifying source files or running (forge/reset) will trigger a code reload and system reset. The current system is always stored in forge/sys.

Enjoy your workflow!

The template folder in this repo provides the absolute smallest starting core. Copy it to start playing around.


The most important stuff is listed here. To dig deeper, check the source. It's simple and hackable.

All functions here are thread-safe and idempotent.


Tells Forge where to find your create-system function after a namespace refresh. Needs to be called once before using reset. start-development! also sets this.

(forge/set-system-symbol! `create-system)


Stores the current system. Gets modified by reset and reset-system!. Can be used to avoid passing the system everywhere. Also convenient in the REPL.



Starts auto-reload and other goodies. Run it once after launching the REPL. See Usage for example code.


Reloads modified namespaces, recreates and restarts the system. Must be called after set-system-symbol! or start-development!.

After one start-development! call, reset runs automatically on every source change.

; once
(forge/start-development! {:system-symbol `create-system})


Recreates and restarts the system, storing the result in #'forge/sys. In development, use reset instead of this.

Define your "create-system" function. It must take one argument, the previous version of the system, and return the next version without starting it.

Handles exceptions carefully:

  • exception when stopping → store the partially stopped system so you can fix it manually

  • exception when starting → stop the partially started system, store the remainder

The latter can be convenient when debugging production failures. If any component fails to start, the rest won't keep the JVM from shutting down.

(defn create-system [prev-system]

(defn -main []
  (try (forge/reset-system! create-system)
    (catch Throwable err
      (binding [*out* *err*] (prn err))
      (System/exit 1))))


Optional Ring middleware for auto-refresh and error rendering. Add to your middleware stack as an outer layer, typically just before the 500 handler:

(def handler
  (-> routes
      ... other middleware ...

Running restart-system! or reset will refresh any open webpages.


Refreshes any modified namespaces. This is a version of that works in background threads, so it's usable in filesystem watchers, HTTP handlers, etc. Used internally by reset.


; works
(future (forge/refresh-namespaces))

Note: unlike (require 'my-ns :reload), this completely replaces namespace objects, breaking defonce. To preserve state, keep it in your System and migrate between system resets. If you have sufficiently good reasons, you can opt a namespace out of "hard" reload into "soft" reload:

(ns my-ns
    [ :refer [disable-unload!]]))


(defonce blah blah)


For lower-level stuff, please run (dir com.mitranim.forge) and check the source; it's annotated and self-explanatory.



Avoid double status notification on reset.


More reliable webpage reloading. Now uses websockets to avoid a few edge cases in long polling.




Feedback, criticism, suggestions, and pull requests are welcome!

Open an issue or reach me on skype:mitranim.web or


Support library for Clojure servers built on the System/Component pattern







No releases published


No packages published