nREPL Clients

Most of the time, you will connect to an nREPL server using an existing client/tool. Tools that support nREPL include:

  • CIDER (Clojure Interactive Development Environment that Rocks for Emacs)

  • Cursive (Clojure IDE/plugin for IntelliJ Idea)

  • Counterclockwise (Clojure IDE/plugin for Eclipse)

  • monroe (nREPL client for Emacs, works with non-Clojure servers)

  • fireplace.vim (Clojure + nREPL support for vim)

  • grenchman (command-line nREPL client written in OCaml, works with non-Clojure servers)

  • vim-iced (Clojure Interactive Development Environment for Vim8/Neovim)

  • Proto REPL (Clojure development environment and REPL for Atom)

  • Calva (Clojure & ClojureScript support for VS Code)

  • REPL-y (command-line client for nREPL)

  • rep (A single-shot nREPL client designed for shell invocation.)

  • shevek (A command-line nREPL client written in Fennel, works with non-Clojure servers)

  • node-nrepl-client (An nREPL client for programmatic use from node.js written in Javascript)

  • Parle (A command-line nREPL client using node.js written in ClojureScript)

  • R-nREPL (nREPL client for R)

  • miracle (fork of monroe targeting Arcadia)

  • Acid.nvim (Asynchronous Clojure Interactive Development for Neovim)

Some of these clients will only work with Clojure nREPL servers, while others are built with language-agnosticism and can connect to nREPL servers written in any language.

Both Leiningen and Boot use internally REPL-y, as their command-line nREPL client.

If your preferred Clojure development environment supports nREPL, you’re done. Use it or connect to an existing nREPL endpoint, and you’re done.

Using the built-in client

nREPL ships with a very simple command-line client that you can use for some basic interactions with the server. The following command will start an nREPL server and connect with it using the built-in client.

$ clj -Sdeps '{:deps {nrepl {:mvn/version "0.7.0"}}}' -m nrepl.cmdline --interactive
nREPL server started on port 59403 on host 127.0.0.1 - nrepl://127.0.0.1:59403
nREPL 0.7.0
Clojure 1.9.0
Java HotSpot(TM) 64-Bit Server VM 10.0.1+10
user=> (+ 1 2)
3

If you want to connect to a server that’s already running you can do it like this:

$ clj -Sdeps '{:deps {nrepl {:mvn/version "0.7.0"}}}' -m nrepl.cmdline --connect --host host --port port
nREPL 0.7.0
Clojure 1.9.0
Java HotSpot(TM) 64-Bit Server VM 10.0.1+10
user=> (+ 1 2)
3

Most users, however, are advised to use REPL-y or their favourite editor instead for optimal results.

Talking to an nREPL endpoint programmatically

If you want to connect to an nREPL server using the default transport, something like this will work:

=> (require '[nrepl.core :as nrepl])
nil
=> (with-open [conn (nrepl/connect :port 59258)]
     (-> (nrepl/client conn 1000)    ; message receive timeout required
         (nrepl/message {:op "eval" :code "(+ 2 3)"})
         nrepl/response-values))

If your nREPL server is running on a different machine or listening on a specific address different than the default one, you can use the :host keyword in the connect function to specify which address to connect to. E.g., to connect to a nREPL server listening on address 172.18.0.5 and port 4001:

=> (with-open [conn (nrepl/connect :host "172.18.0.5" :port 4001)]
     (-> (nrepl/client conn 1000)    ; message receive timeout required
         (nrepl/message {:op "eval" :code "(+ 2 3)"})
         nrepl/response-values))

response-values will return only the values of evaluated expressions, read from their (by default) pr-encoded representations via read. You can see the full content of message responses easily:

=> (with-open [conn (nrepl/connect :port 59258)]
     (-> (nrepl/client conn 1000)
         (nrepl/message {:op "eval" :code "(time (reduce + (range 1e6)))"})
         doall      ;; `message` and `client-session` all return lazy seqs
         pprint))
nil
({:out "\"Elapsed time: 68.032 msecs\"\n",
  :session "2ba81681-5093-4262-81c5-edddad573201",
  :id "3124d886-7a5d-4c1e-9fc3-2946b1b3cfaa"}
 {:ns "user",
  :value "499999500000",
  :session "2ba81681-5093-4262-81c5-edddad573201",
  :id "3124d886-7a5d-4c1e-9fc3-2946b1b3cfaa"}
 {:status ["done"],
  :session "2ba81681-5093-4262-81c5-edddad573201",
  :id "3124d886-7a5d-4c1e-9fc3-2946b1b3cfaa"})

Each message must contain at least an :op (or "op") slot, which specifies the "type" of the operation to be performed. The operations supported by an nREPL endpoint are determined by the handlers and middleware stack used when starting that endpoint; the default middleware stack (described below) supports a particular set of operations, detailed here.