Clojure Guide — nREPL: Interactive Development Server
In this tutorial, you will learn about Clojure Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
nREPL is a Clojure network REPL protocol and server that connects editors, IDEs, and development tools to a running Clojure Process for interactive programming, debugging, and hot-reloading.
What You'll Learn
- What nREPL is and how it works
- Setting up nREPL with Leiningen and deps.edn
- Connecting from Emacs, Cursive, and VSCode
- nREPL middleware and extensions
- Hot-reloading code in a running process
Why It Matters
nREPL is the foundation of interactive Clojure development. Instead of edit-compile-run cycles, you connect your editor to a live process and evaluate code instantly. Doda Browser uses nREPL for its plugin development workflow.
Real-World Use
Every major Clojure editor uses nREPL: CIDER (Emacs), Cursive (IntelliJ), Calva (VSCode). It powers REPL-driven development used by Netflix, Walmart, and CircleCI.
flowchart LR
A["nREPL"] --> B["Server Setup"]
B --> C["Editor Connection"]
C --> D["Middleware"]
D --> E["Workflow"]
A:::current --> B
style A fill:#2563eb,stroke:#2563eb,color:#fff
style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b
Starting nREPL
;; With Leiningen
lein repl
;; Starts nREPL server on port 61123 (random)
;; With deps.edn
clj -M -m nrepl.cmdline
;; Or with aliases
clj -M:repl
;; Start with specific port
lein repl :start :port 7888
Connecting from Emacs (CIDER)
;; In project.clj
:plugins [[cider/cider-nrepl "0.28.0"]]
;; Emacs commands
M-x cider-jack-in ; Start and connect
M-x cider-connect ; Connect to running server
C-c C-k ; Evaluate current file
C-c C-e ; Evaluate sexp before cursor
C-c M-j ; Eval last sexp in buffer
Connecting from Cursive
;; IntelliJ/Cursive
;; 1. Run > Edit Configurations
;; 2. Add new Clojure REPL configuration
;; 3. Set type to "Remote"
;; 4. Connect to localhost:7888
;; Or start from Cursive:
;; Run > Run 'Clojure REPL' for project
Connecting from VSCode (Calva)
;; Calva commands
Ctrl+Alt+C Ctrl+Alt+J ; Start REPL
Ctrl+Alt+C Enter ; Evaluate current form
Ctrl+Alt+C E ; Evaluate current top-level form
Ctrl+Alt+C R ; Load current file
;; Calva connects to nREPL automatically
nREPL Middleware
;; project.clj with middleware
:plugins [[cider/cider-nrepl "0.28.0"]
[refactor-nrepl "3.5.0"]]
;; Custom middleware
(defn my-middleware [handler]
(fn [msg]
(println "nREPL request:" (:op msg))
(handler msg)))
REPL-Driven Workflow
;; 1. Start REPL (connected to editor)
;; 2. Write function
(defn process-data [data]
(->> data
(filter :active)
(map :name)
(take 10)))
;; 3. Evaluate in REPL (C-c C-e in CIDER)
;; 4. Test immediately
(process-data [{:name "Alice" :active true}
{:name "Bob" :active false}])
;; => ("Alice")
;; 5. Refine function
(defn process-data [data limit]
(->> data
(filter :active)
(map :name)
(take limit)))
;; 6. Re-evaluate and test
(process-data [{:name "Alice" :active true}
{:name "Bob" :active false}] 5)
Hot Reloading
(require '[clojure.tools.namespace.repl :refer [refresh]])
;; Reload changed namespaces
(refresh)
;; Reload with error handling
(try
(refresh)
(catch Exception e
(println "Refresh failed:" (.getMessage e))))
;; Automatic reload on file change
(require '[clj-reload.core :as reload])
(reload/start)
Debugging with nREPL
;; Set breakpoint
(require '[cider.nrepl.middleware.debug :refer [breakpoint]])
(defn compute [x y]
(let [result (breakpoint (* x y))]
(str "Result: " result)))
;; CIDER debugger keys:
;; n - next
;; c - continue
;; q - quit
;; e - eval
;; p - print value
Common Mistakes
1. Forgetting to start nREPL
Make sure nREPL is running before trying to connect from your editor. Check the port number.
2. Port conflicts
Multiple nREPL instances on the same port cause connection issues. Use unique ports or let nREPL choose randomly.
3. Not refreshing after changes
Evaluate changed files with c-c c-k (CIDER) or use tools.namespace.repl/refresh for full reload.
4. State accumulation
Long-running REPLs accumulate stale state. Periodically restart the REPL process for a clean state.
5. Blocking the REPL
Long-running operations block the REPL. Use future for expensive computations.
Practice Questions
1. What is nREPL? A network REPL protocol and server that enables connecting editors and tools to a running Clojure process for interactive evaluation.
2. How does REPL-driven development work? You write functions, evaluate them in the running REPL, test immediately, refine, and re-evaluate without restarting the process.
3. What is cider-nrepl? A collection of nREPL middleware that adds debugging, inspection, completion, and other IDE features to the basic nREPL server.
Challenge: Set up nREPL with CIDER and demonstrate a REPL-driven workflow for developing a data processing pipeline.
FAQ
{{< faq question="Is nREPL only for Clojure?" >}} nREPL is primarily for Clojure, but it also supports ClojureScript (via Piggieback) and other JVM languages through custom middleware. {{< /faq >}}
{{< faq question="What port does nREPL use?" >}}
By default, nREPL uses a random port. You can specify a port with :port option or set it in project.clj with :repl-options {:port 7888}.
{{< /faq >}}
{{< faq question="Is nREPL secure?" >}} nREPL gives full access to the JVM process. Never expose it to external networks. Use SSH tunneling for remote connections. {{< /faq >}}
{{< faq question="Can I have multiple nREPL connections?" >}} Yes, multiple editors or tools can connect to the same nREPL server simultaneously. Each connection has its own session. {{< /faq >}}
{{< faq question="What is the difference between nREPL and Socket REPL?" >}} Socket REPL is a simpler REPL built into Clojure 1.8+. nREPL has more features (middleware, multiple sessions, editor integration) at the cost of more complexity. {{< /faq >}}
Mini Project
Create a project.clj with nREPL and hot-reload configuration:
(defproject my-repl-project "0.1.0"
:dependencies [[org.clojure/clojure "1.11.1"]
[org.clojure/tools.namespace "1.3.0"]]
:profiles {:dev {:dependencies [[cider/cider-nrepl "0.28.0"]]
:plugins [[cider/cider-nrepl "0.28.0"]]
:source-paths ["dev"]}}
:repl-options {:init-ns dev
:init (do
(require 'clojure.tools.namespace.repl)
(println "REPL started. Use (refresh) to reload."))})
What's Next
Now that you understand nREPL, explore ClojureScript for running Clojure in the browser.
| Topic | Description | Link |
|---|---|---|
| Clojure ClojureScript | Clojure for the browser | {{< ref "27-clojurescript" >}} |
| Clojure GraalVM | Native compilation | {{< ref "28-graalvm" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro