Up and Running

To use CIDER, you’ll need to connect it to a running nREPL server that is associated with your program. Most Clojure developers use standard build tooling such as tools.deps, Leiningen, or Gradle, and CIDER can automatically work with those tools to get you up and running quickly. But those tools are not required; CIDER can connect to an nREPL server that is already started and is managed separately.

CIDER will automatically work with Leiningen 2.9.0+ or a recent tools.deps. Older versions are not supported.

There are two ways to connect CIDER to an nREPL server:

  1. CIDER can launch an nREPL server for your project from Emacs.

  2. You can connect CIDER to an already-running nREPL server, managed separately.

The following sections describe each of these methods.

Launch an nREPL Server From Emacs

If you have a Clojure project in your file system and want CIDER to launch an nREPL session for it, simply visit a file that belongs to the project, and type M-x cider-jack-in RET.[1] CIDER will start an nREPL server and automatically connect to it.

In Clojure(Script) buffers the command cider-jack-in is bound to C-c C-x (C-)j (C-)j.

If you pause after typing C-c C-x, a menu (cider-start-menu) pops up listing all the ways to start or connect to a session - the jack-in commands, the connect commands and the sibling-connect commands - so you don’t have to remember each full key sequence. The menu also has three arguments that apply to the jack-in commands for that invocation only, without touching your saved configuration:

  • -a (--aliases=) - the Clojure CLI aliases to launch with (e.g. :dev:test)

  • -l (--cljs-repl=) - the ClojureScript REPL type to use

  • -e (--edit-command) - edit the final command in the minibuffer before it runs

Typing a full sequence like C-c C-x j j still fires immediately; the menu only appears if you pause after the prefix.

The process of jacking-in is pretty simple:

  • CIDER determines the build system for your project (e.g. Leiningen) and picks the necessary command to start an nREPL server.

  • CIDER shells out and runs a command like lein repl :headless to start an nREPL server.

  • CIDER waits for the nREPL server to start. CIDER figures out this by parsing the output from the command and waiting for a line like nREPL server started on port 53005 on host localhost - nrepl://localhost:53005 to appear there.

  • CIDER extracts the port of the nREPL from the preceding message.

  • It connects to the running nREPL server.

You can see the exact command that cider-jack-in invoked in your minibuffer, while waiting for nREPL to start. You can also find this command in Emacs’s *Messages* buffer.

In some cases one project might have multiple project markers in it - e.g. project.clj and deps.edn. When this happens CIDER will prompt you to select the build tool to use. You can override this behavior by setting the variable cider-preferred-build-tool. While you can set it globally in your Emacs config, most of the time you’d probably want to have a project-specific setting for it in your .dir-locals.el:

((clojure-mode
  (cider-preferred-build-tool . lein)))
cider-jack-in is mainly designed for local development (with files on a local machine and the nREPL process running on the same machine). It does support various common remote/container scenarios, covered in Remote and Container Connections. Due to the large variation of remote scenarios it cannot support all of them, so in some cases, a better option would be to start nREPL manually and connect to it with cider-connect.

Auto-Injecting Dependencies

While CIDER’s core functionality requires nothing more than an nREPL server, there are many advanced features that depend on the presence of additional nREPL middleware. Fortunately, if you’re using cider-jack-in, that’s handled auto-magically.

If your project uses lein or tools.deps (deps.edn), CIDER will automatically inject all the necessary nREPL dependencies (e.g. cider-nrepl or piggieback) when it starts the server. The injection process is extremely simple - CIDER passes the extra dependencies and nREPL configuration to your build tool in the command it runs to start the nREPL server. Here’s how this looks for tools.deps:

$ clojure -Sdeps '{:deps {nrepl {:mvn/version "1.7.0"} cider/cider-nrepl {:mvn/version "0.59.0"}}}' -m nrepl.cmdline --middleware '["cider.nrepl/cider-middleware"]'
If you don’t want cider-jack-in to inject dependencies automatically, set cider-inject-dependencies-at-jack-in to nil. Note that you’ll have to setup the dependencies yourself (see nREPL Middleware Setup).

Normally cider-jack-in would inject only cider-nrepl and cider-jack-in-cljs would add piggieback as well. The injection mechanism is configurable and you can easily add more libraries there. Some CIDER extensions would use this mechanism to auto-inject their own dependencies.

Here’s how you can modify the injected dependencies for cider-jack-in-clj:

;; auto-inject version 1.0 of the library foo/bar
(cider-add-to-alist 'cider-jack-in-dependencies
                    "foo/bar" "1.0")
;; if you want to have full control over the coordinate description set it as an alist
;; auto-inject {:git/sha "6ae2b6f71773de7549d7f22759e8b09fec27f0d9" for library org.clojure/tools.deps
;;              :git/url "https://github.com/clojure/tools.deps/"}
(cider-add-to-alist 'cider-jack-in-dependencies
                    "org.clojure/tools.deps"
                    '(("git/sha" . "6ae2b6f71773de7549d7f22759e8b09fec27f0d9")
                      ("git/url" . "https://github.com/clojure/tools.deps/")))
Always use the fully qualified group/artifact (e.g. re-frame/re-frame) in these dependencies, since only Leiningen supports the bare re-frame syntax.

CIDER will also inject the most recent version of nREPL that it supports. This is a simple trick to override the version of nREPL bundled with your build tool (e.g. Leiningen), so you can gain access to the newest nREPL features. Generally that’s one aspect of CIDER’s inner workings that end-users will rarely have to think about.

You can override the injected versions of cider-nrepl and nREPL by customizing cider-injected-middleware-version and cider-injected-nrepl-version. Generally you should avoid doing this, but it may be useful if you want to try a newer version or you encounter some regression that forces you to temporarily use an older version.

CIDER can also inject a Clojure dependency into your project, which is useful, for example, if your project defaults to an older version of Clojure than that supported by the CIDER middleware. Set cider-jack-in-auto-inject-clojure appropriately to enable this.

Enabling nREPL JVMTI agent

Since version 1.2.0, nREPL includes a native JVMTI agent which makes the eval interrupts work properly on Java 21 and later. To enable the agent, the Java process should be launched with -Djdk.attach.allowAttachSelf. CIDER will do it automatically during jack-in if cider-enable-nrepl-jvmti-agent variable is set to t.

cider-enable-nrepl-jvmti-agent has no effect if you start a REPL process outside of Emacs and connect to it with cider-connect. In that scenario, you have to add -Djdk.attach.allowAttachSelf Java property manually through the means of the build tool. In Leiningen, add this to project.clj:

:jvm-opts ["-Djdk.attach.allowAttachSelf"]

In tools.deps, add this to one of the aliases that you enable with the REPL:

:aliases {:dev
          {:jvm-opts ["-Djdk.attach.allowAttachSelf"]
           ...}}

Jacking-in without a Project

If you try to run cider-jack-in outside a project directory, CIDER will warn you and ask you to confirm whether you really want to do this; more often than not, this is an accident. If you decide to proceed, CIDER will invoke the tool configured in cider-jack-in-default. When that variable is nil (the default), CIDER auto-detects at jack-in time, picking clojure-cli if clojure is on PATH, otherwise falling back to lein.

You can set cider-allow-jack-in-without-project to t if you’d like to disable the warning displayed when jacking-in outside a project.

Universal jack-in

cider-jack-in-universal C-c C-x j u is another way to quickly jack in without a project choosing from a list of pre-configured Clojure build tools. When this command is called from outside of a project, the user is given the option to select to jack in with one of the pre-configured tools, as well as to confirm the root directory to use as a base. If the command is called from within a project directory, it behaves exactly the same as cider-jack-in does.

It utilizes Emacs’s numeric prefix arguments to quickly jack in with a specific build tool. Numeric prefix arguments can be set with the Meta key followed by a number.

The following Clojure build tools are supported so far

  • M-1 C-c C-x j u jack-in using clojure-cli.

  • M-2 C-c C-x j u jack-in using leiningen.

  • M-3 C-c C-x j u jack-in using babashka.

  • M-4 C-c C-x j u jack-in using nbb.

  • M-5 C-c C-x j u jack-in using basilisp.

Here is an example of how to bind F12 for quickly bringing up a babashka REPL:

(global-set-key (kbd "<f12>") (lambda ()
                                (interactive)
                                (cider-jack-in-universal 3)))

The set of available tools is the subset of cider-jack-in-tools that declare a :dispatch-prefix-arg. Each tool entry is registered via cider-register-jack-in-tool and looks like this:

(cider-register-jack-in-tool 'nbb
                             :command-var 'cider-nbb-command
                             :params-var 'cider-nbb-parameters
                             :project-files '("nbb.edn")
                             :resolver #'cider--resolve-prefix-command
                             :dispatch-prefix-arg 4
                             :jack-in-type 'cljs
                             :cljs-repl-type 'nbb)

The keys in the property list:

  • :command-var and :params-var — variable symbols holding the executable name and the params string.

  • :project-files — file names that mark a project of this type.

  • :resolver — optional, defaults to cider—​resolve-command. Use cider—​resolve-prefix-command for npx X style invocations or cider—​resolve-project-command for project-relative scripts.

  • :inject-fn — optional, function (PARAMS PROJECT-TYPE COMMAND) that returns PARAMS with REPL deps injected. Tools without one (e.g. babashka, nbb, basilisp) skip injection.

  • :dispatch-prefix-arg, :jack-in-type, :cljs-repl-type — used by cider-jack-in-universal to dispatch. Tools without a :dispatch-prefix-arg are not selectable through that command.

You can register additional tools, or replace existing ones, with the same call.

Customizing the Jack-in Command Behavior

You can use C-u M-x cider-jack-in RET to specify the exact command that cider-jack-in would run. This option is very useful if you want to e.g. specify extra Leiningen profiles or deps.edn aliases.

Alternatively you can C-u C-u M-x cider-jack-in RET, which is a variation of the previous command. This command will first prompt you for the project you want to launch cider-jack-in in, which is pretty handy if you’re in some other directory currently. This option is also useful if your project contains some combination of project.clj and deps.edn and you want to launch a REPL for one or the other.

The examples use only cider-jack-in, but this behavior is consistent for all cider-jack-in-\* commands.

You can further customize the command line CIDER uses for cider-jack-in by modifying some options. Those differ a bit between the various tools, so we’ll examine them tool by tool.

If instead you want to bypass command construction entirely and run a command of your own, see Overriding the Jack-In Command below.

Leiningen Options

  • cider-lein-command - the name of the Leiningen executable (lein by default)

  • cider-lein-parameters - the command-line params to start a REPL (e.g. repl :headless or -o to enable offline mode)

Clojure CLI Options

  • cider-clojure-cli-command - the name of the clojure executable (clojure by default)

  • cider-clojure-cli-parameters - the command-line parameters to start a REPL

  • cider-clojure-cli-aliases - a list of project-specific aliases to be used at jack-in time (it’s meant to be set via .dir-locals.el)

  • cider-clojure-cli-global-aliases - a list of global aliases that are appended to project-specific cider-clojure-cli-aliases

When cider-clojure-cli-aliases is unset, CIDER hints at jack-in time that you may want to activate an alias (e.g. :dev or :test). If you deliberately jack in without aliases, set cider-clojure-cli-aliases to :nil-no-warn to silence the hint.

On MS-Windows, CIDER will employ PowerShell to execute Clojure if no clojure executable is found in the PATH (e.g. like the one supplied by deps.clj). The default executable used is powershell which is available on all Windows platforms. Using PowerShell will Base64 encode the clojure launch command before passing it to PowerShell and avoids shell-escaping issues.

Set cider-clojure-cli-powershell-options to pass extra options to the PowerShell executable itself (inserted before the encoded command). For example, -noprofile -executionpolicy bypass skips the user profile and works around a restrictive execution policy.

The functionality of cider-clojure-cli-command has been verified with the following alternatives

  • pwsh: This option proves beneficial when the user has installed the ClojureTools module on pwsh in a directory not accessible by the system’s PowerShell installation.

  • deps.exe: This executable is part of the tools provided by deps.clj as an alternative name for clojure.exe.

Alternatively you can use WSL (e.g. to run nREPL and Emacs there), which will likely result in a better overall development experience.

How the Clojure CLI Command Is Built

CIDER doesn’t run your aliases with -X or -A. Instead it injects an inline :cider/nrepl alias whose :main-opts start the nREPL server, and invokes it with -M. A typical jack-in command ends up looking like this:

clojure -Sdeps '{:deps {...}}' -M:dev:cider/nrepl

Aliases you add via cider-clojure-cli-aliases (project-local, usually set in .dir-locals.el) or cider-clojure-cli-global-aliases (global) are concatenated into that -M…​:cider/nrepl form. A leading -A, -M, -T, or -X is stripped from each alias, since CIDER picks the exec flag and you only supply the alias names.

For example, to enable your project’s :dev alias at jack-in:

;; .dir-locals.el
((clojure-mode
  (cider-clojure-cli-aliases . ":dev")))

Because CIDER bootstraps nREPL through :main-opts, jack-in is inherently -M-based. That’s fine for aliases that contribute :extra-deps, :extra-paths, or :jvm-opts, as those take effect no matter which exec flag is used. It does not work for exec-style aliases that rely on an :exec-fn (the ones you’d normally run with -X). If you need such an alias to set up your environment, start the nREPL server yourself (e.g. via a clojure -X:dev invocation that launches an nREPL server with the CIDER middleware) and then use cider-connect instead of cider-jack-in.

Gradle Options

  • cider-gradle-command - the name of the Gradle executable (./gradlew by default)

  • cider-gradle-parameters - the Gradle arguments to invoke the repl task (e.g. --no-daemon or --configuration-cache) (clojureRepl by default)

shadow-cljs

  • cider-shadow-cljs-command - the command to run shadow-cljs (npx shadow-cljs by default). By default we favor the project-specific shadow-cljs over the system-wide.

  • cider-shadow-cljs-parameters - the task to start a REPL server (server by default)

Overriding the Jack-In Command

Which jack-in command is used is normally inferred from the project type, but you can override it for full control over how CIDER starts the nREPL server. An overriding command is used verbatim: it bypasses project-type detection, the resolver, and dependency injection. This is the simplest escape hatch when CIDER’s auto-derivation does the wrong thing, which is common inside containers, on TRAMP, or when you need a custom wrapper script.

The precedence order for determining the jack-in command is:

  1. :jack-in-cmd passed as a parameter,

  2. cider-jack-in-cmd set as a (directory-local) variable, and

  3. the command inferred from the project type (the default).

Since the command is used verbatim, it has to start an nREPL server with the cider-nrepl middleware itself; CIDER won’t inject the dependencies for you in this case.

Via a directory-local variable

Set cider-jack-in-cmd to a complete command line, typically in .dir-locals.el:

;; .dir-locals.el
((nil . ((cider-jack-in-cmd . "ssh my-box -t bb nrepl-server localhost:0"))))

Via a parameter

You can also pass the command programmatically as the :jack-in-cmd parameter of cider-jack-in-\*. For example, a dedicated command that starts an nbb REPL:

(defun cider-jack-in-nbb-2 ()
  "Start a Cider nREPL server with the 'nbb nrepl-server' command."
  (interactive)
  (cider-jack-in-clj '(:jack-in-cmd "nbb nrepl-server")))

Starting an nREPL Server Without Connecting

In some situations, it might be useful to only start an nREPL server process, without connecting to it. This can support complex setups for which CIDER cannot reliably detect which server/port to connect to, and would therefore fail. This assumes that you will run cider-connect manually afterwards, specifying the host/port.

For this scenario, the cider-start-nrepl-server (C-c C-x (C-)j (C-)n) command is provided, which takes the same parameters as cider-jack-in.

Connect to a Running nREPL Server

If you have an nREPL server already running, CIDER can connect to it. For instance, if you have a Leiningen-based project, go to your project’s directory in a terminal session and type:

$ lein repl :headless

This will start the project’s nREPL server.

It is also possible for plain clj, although the command is somewhat longer:

$ clj -Sdeps '{:deps {cider/cider-nrepl {:mvn/version "0.59.0"}}}' -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]"

Alternatively, you can start nREPL either manually or using the facilities provided by your project’s build tool (Gradle, Maven, etc).

After you get your nREPL server running, go back to Emacs and connect to it: M-x cider-connect RET. CIDER will prompt you for the host and port information, which should have been printed when the previous commands started the nREPL server in your project.

In Clojure(Script) buffers the command cider-connect is bound to C-c C-x c s.

If you frequently connect to the same hosts and ports, you can tell CIDER about them and it will use the information to do completing reads for the host and port prompts when you invoke cider-connect. You can identify each host with an optional label.

(setq cider-known-endpoints
  '(("host-a" "10.10.10.1" "7888")
    ("host-b" "7888")))

If you wish to bypass the prompts entirely, you can configure the variables cider-connect-default-params and cider-connect-default-cljs-params on a per-project basis using .dir-locals.el.

The following configuration allows you to type M-x cider-connect-clj&cljs RET and instantly connect to both JVM and shadow-cljs REPLs without answering any prompts – useful when the project always uses the same fixed endpoints for its nREPL servers.

---
((clojure-mode
  . ((cider-connect-default-params . (:host "localhost" :port 1234))
     (cider-connect-default-cljs-params . (:host "localhost" :port 5678))
     (cider-default-cljs-repl . shadow))))
---

Note that the universal argument C-u can be used before a command to override these settings and force the prompts to be displayed.

Beyond the Local Machine

The commands above assume the nREPL server runs on your own machine. For servers on another host, inside a container, or reachable over a Unix domain socket - including SSH tunneling and jacking in over TRAMP - see Remote and Container Connections.

What’s Next?

So, what to do next now that CIDER’s ready for action? Here are a few ideas:


1. Yeah, that’s a "Neuromancer" reference.