Tools.nrepl
A Clojure network REPL that provides a server and client, along with some common APIs of use to IDEs and other tools that may need to evaluate Clojure code in remote environments.
Install / Use
/learn @clojure/Tools.nreplREADME
nREPL
This project's development moved to a new nrepl/nrepl repository, outside of Clojure Contrib, after version 0.2.13
nREPL is a Clojure network REPL that provides a REPL server and client, along with some common APIs of use to IDEs and other tools that may need to evaluate Clojure code in remote environments.
Usage
"Installation" <a name="installing"/>
nREPL is available in Maven central. Add this to your Leiningen
project.clj :dependencies:
[org.clojure/tools.nrepl "0.2.13"]
Or, add this to your Maven project's pom.xml:
<dependency>
<groupId>org.clojure</groupId>
<artifactId>tools.nrepl</artifactId>
<version>0.2.13</version>
</dependency>
A list of all prior releases are available here.
Please note the changelog in CHANGELOG.md.
nREPL is compatible with Clojure 1.2.0 and higher.
Please post general questions or discussion on either the clojure-dev or clojure-tools mailing lists. Bug reports and such may be filed into nREPL's JIRA.
nREPL's generated API documentation is available here. A history of nREPL builds is available, as well as a compatibility test matrix, verifying nREPL's functionality against multiple versions of Clojure and multiple JVMs.
Connecting to an nREPL server
Most of the time, you will connect to an nREPL server using an existing client/tool. Tools that support nREPL include:
- Leiningen (starting with v2)
- Counterclockwise (Clojure IDE/plugin for Eclipse)
- Cursive (Clojure IDE/plugin for IntelliJ Idea)
- cider (Clojure IDE and REPL for Emacs)
- monroe (nREPL client for Emacs)
- fireplace.vim (Clojure + nREPL support for vim)
- Reply
- Atom
- clojupyter (Jupyter notebooks for Clojure)
If your preferred Clojure development environment supports nREPL, you're done. Use it or connect to an existing nREPL endpoint, and you're done.
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 '[clojure.tools.nrepl :as repl])
nil
=> (with-open [conn (repl/connect :port 59258)]
(-> (repl/client conn 1000) ; message receive timeout required
(repl/message {:op "eval" :code "(+ 2 3)"})
repl/response-values))
[5]
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 (repl/connect :port 59258)]
(-> (repl/client conn 1000)
(repl/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.
Embedding nREPL, starting a server
If your project uses Leiningen (v2 or higher), you already have access to an
nREPL server for your project via lein repl (or, lein repl :headless if you
don't need the Reply terminal-based nREPL client to connect to the resulting
nREPL server).
Otherwise, it can be extremely useful to have your application host a REPL server whereever it might be deployed; this can greatly simplify debugging, sanity-checking, panicked code patching, and so on.
nREPL provides a socket-based server that you can trivially start from your application. Add it to your project's dependencies, and add code like this to your app:
=> (use '[clojure.tools.nrepl.server :only (start-server stop-server)])
nil
=> (defonce server (start-server :port 7888))
#'user/server
Depending on what the lifecycle of your application is, whether you want to be
able to easily restart the server, etc., you might want to put the value
start-server returns into an atom or somesuch. Anyway, once your app is
running an nREPL server, you can connect to it from a tool like Leiningen or
Counterclockwise or Reply, or from another Clojure process:
=> (with-open [conn (repl/connect :port 7888)]
(-> (repl/client conn 1000)
(repl/message {:op :eval :code "(+ 1 1)"})
repl/response-values))
[2]
You can stop the server with (stop-server server).
Server options
Note that nREPL is not limited to its default messaging protocol, nor to its default use of sockets. nREPL provides a transport abstraction for implementing support for alternative protocols and connection methods. Alternative transport implementations are available, and implementing your own is not difficult; read more about transports here.
Building nREPL
Releases are available from Maven Central, and SNAPSHOT builds from master's HEAD are automatically deployed to Sonatype's OSS repository (see this for how to configure Leiningen or Maven to use OSS-snapshots), so building nREPL shouldn't ever be necessary. But, if you insist:
- Clone the repo
- Make sure you have maven installed
- Run the maven build, either:
mvn package: This will produce an nREPL jar file in thetargetdirectory, and run all tests against Clojure 1.2.0.mvn verify: This does the same, but also runs the tests with other Clojure "profiles" (one for each supported version of Clojure).
Why nREPL?
nREPL has been designed with the aim of ensuring that it satisfies the requirements of both application developers (in support of activities ranging from interactive remote debugging and experimentation in development contexts through to more advanced use cases such as updating deployed applications) as well as toolmakers (providing a standard way to connect to and introspect running environments as a way of informing user interfaces of all kinds, including "standard" interactive, text-based REPLs).
The default network protocol used is simple, depending neither on JVM or Clojure specifics, thereby allowing (encouraging?) the development of non-Clojure REPL clients. The REPLs operational semantics are such that essentially any non-JVM Clojure implementation should be able to implement it, with allowances for hosts that lack the concurrency primitives to support e.g. asynchronous evaluation, interrupts, etc.
For more information about the motivation, architecture, use cases, and discussion related to nREPL, see the see the original design notes, available here, and the notes and discussion around its recent redesign.
Design
nREPL largely consists of three abstractions: handlers, middleware, and transports. These are roughly analogous to the handlers, middleware, and adapters of Ring, though there are some important semantic differences. Finally, nREPL is fundamentally message-oriented and asynchronous (in contrast to most REPLs that build on top of streams provided by e.g. terminals).
Messages
nREPL messages are maps. The keys and values that may be included in messages depends upon the transport being used; different transports may encode messages differently, and therefore may or may not be able to represent certain data types.
Each message sent to an nREPL endpoint constitutes a "request" to perform a
particular operation, which is indicated by a "op" entry. Each operation may
further require the incoming message to contain other data. Which data an
operation requires or may accept varies; for example, a message to evaluate
some code might look like this:
{"op" "eval" "code" "(+ 1 2 3)"}
The result(s) of performing each operation may be sent back to the nREPL client in one or more response messages, the contents of which again depend upon the operation.
Transports <a name="transports"/>
<!-- talk about strings vs. bytestrings, the encoding thereof, etc when we figure that out -->Transports are roughly analogous to Ring's adapters: they provide an
implementation of a common protocol (clojure.tools.nrepl.transport.Transport)
to enable nREPL clients and servers to send and receive messages without regard
for the underlying channel or particulars of message encoding.
nREPL incl
Related Skills
node-connect
339.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
339.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.9kCommit, push, and open a PR
