Configure REPL on Startup

A Clojure REPL starts in the user namespace by default. Clojure automatically loads code from a user.clj file when found on the class path.

The user.clj file typically contains tools to support development, such as:

  • loading project code into the REPL by requiring namespaces
  • call functions to run an application or service
  • start components (i.e for mount, component, integrant)
  • adding development tools - portal data inspector

The user.clj is typically placed in a dev folder within the root of the project, to keep it separated from production code.

Example project

practicalli/clojure-configure-repl project contains example code for configuring the REPL start up

juxt/edge has example projects using the same technique.

Create a dev/user.clj file and :env/dev alias

Create a dev/user.clj file with a namespace called user.

user.clj should include a namespace definition

(ns user)

practicalli/clojure-deps-edn includes a :env/dev alias which adds the dev directory to the project classpath. Alternatively, edit the deps.edn file and add the following code:

  {:extra-paths ["dev"]}

Running a Clojure REPL with the :env/dev alias will add the dev/user.clj file to the class path and be loaded by the REPL.

In this example the dev/ path is added to the project and then the REPL is run using Rebel.

clojure -M:env/dev:repl/rebel

Using the dev/ directory

The user.clj code should not be included in live deployments, such as jars and uberjars. Including the dev/ directory via the :env/dev alias keeps the user.clj and any other development only code separate from deployment actions.

Requiring namespaces

By requiring a namespace in the dev/user.clj file, the code defined in that namespace will be loaded into the REPL once started.

Add a require expression to the namespace definition in dev/user.clj

(ns user
  (:require [practicalli.project-namespace]))

Require loads all the expressions into the REPL, so functions are immediately available.

Calling functions

Use the fully qualified function name from the required namespace can be called, to start the application for example.

(ns user
  (:require [practicalli.project-namespace]))


An alias can be used in the require expression, useful if multiple functions from a namespace are to be called

(ns user
  (:require [practicalli.service :as service]))


Fuzzy searching for library dependencies - deps.edn

The find-deps project fuzzy searches Maven Central and Clojars for dependencies when given a name.

The :search/libraries in practicalli/clojure-deps-edn) will add the find-deps library.

Add the find-deps project to and alias called :search/libraries, either in the project or user level deps.edn file.

   {find-deps/find-deps {:git/url ""
                         :git/sha "9bf23a52cb0a8190c9c2c7ad1d796da802f8ce7a"}}
   :main-opts ["-m" "find-deps.core"]}

Require the find-deps.core namespace in the dev/user.clj file to use its deps and print-deps functions

(ns user
  (:require [find-deps.core :as find-deps]))

Start a REPL using the :env/dev and :search/libraries aliases.

To start a Rebel REPL, use the following command in a terminal

clojure -A:env/dev:search/libraries:repl/rebel

Call the (find-deps/deps "library-name") to return a map of the matching dependency, or (find-deps/print-deps "library name") to print dependencies in a table.

  (find-deps/deps "library-name")
  (find-deps/print-deps "library name")

Starting Component Life-cycle Services

Clojure has several library to manage the life-cycle of components that make up the application, especially those components with state. Components can be started and stopped in a specific order.

Example component life-cycle libraries included

In Clojure it is idiomatic to define the component life-cycle services in a namespace called dev. In the dev/user.clj file, add the following ns declaration to require the dev namespace and change to that namespace with in-ns

(ns user
  (:require [dev]))


Now define code in the dev/dev.clj file that controls the component life-cycle services library for the project.

Example project with component life-cycle

Using mount, its common to define a dev.clj file with go, stop and restart functions that manage the life-cycle of mount components. A start function contains the list of components with optional state.

Require the mount namespace and the main namespace for the project, which should contain all the code to start and stop services.

(ns user
  :require [mount.core :refer [defstate]]

Define a start function to start all services

(defn start []
  (mount/start #'

The go function calls start and marks all components as ready.

(defn go
  "Start all states defined by defstate"

The stop function stops all components, removing all non-persistent state.

(defn stop [] (mount/stop))

The reset function that calls stop, refreshes the namespaces so that stale definitions are removed and starts all components (loading in any new code).

(defn reset
  "Stop all states defined by defstate.
  Reload modified source files and restart all states"
  (namespace/refresh :after 'dev/go))

Use dev namespace during development

Require namespace rather than main, to start components in a development environment.


results matching ""

    No results matching ""