nREPL Clients

Most of the time, you will connect to an nREPL server using an existing library/client/tool. Bellow is a listing of many such clients.

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.

Command-line Clients

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

  • 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)

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

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

Editors/IDEs

  • 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)

  • miracle (fork of monroe targeting Arcadia)

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

  • Conjure (Clojure(Script) plugin for Neovim)

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

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

  • Chrorine (Atom plugin for Clojure Development)

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

  • Calva (Clojure & ClojureScript support for VS Code)

  • Tutkain (Clojure plugin for Sublime Text)

If your preferred Clojure development environment supports nREPL, you’re in luck. Just use it or connect to an existing nREPL endpoint and start hacking.

Most Clojure editors/IDEs can start an nREPL server themselves and connect to it automatically (e.g. CIDER would do this when you’re using the cider-jack-in family of commands), so you’ll rarely need to start a server externally for local development purposes.

Libraries

Other Clients

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.9.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.9.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.9.0"}}}' -m nrepl.cmdline --connect --host host --port port
nREPL 0.9.0
Clojure 1.9.0
Java HotSpot(TM) 64-Bit Server VM 10.0.1+10
user=> (+ 1 2)
3

The built in client does not support the tty transport. Use nc or telnet instead.

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.