Managing Connections

Because nREPL connections map one-to-one to REPL buffers in CIDER, for the purpose of this section we use "REPL" and "connection" interchangeably.

Life’s easy when you’re always working only on a single project with a single Clojure connection. If you’re lucky enough to be one of those people then you can safely skip reading this section. Its target audience are people who have to work simultaneously on multiple projects or have multiple connections opened for the same project (e.g. a Clojure and a ClojureScript one).

It turns out that it’s really hard to map reliably operations originating in source buffers (e.g. code evaluation) to the right connection buffer, as there are many things you have to take into account:

  • Is the connection mapped to some project or not?

  • Do you have multiple connections mapped to the same project? (e.g. a Clojure and ClojureScript REPL)

  • Do you have multiple connections of the same type mapped to the same project? (e.g. several Clojure REPLs)

  • What should happen if you try to evaluate code that’s outside of a project?

  • Where should you dispatch operations originating in .cljc files? To the Clojure REPL? The ClojureScript REPL? To both REPLs?

CIDER started out without any support for multiple connections and through the years we’ve had several different ideas on how to support multiple connections:

  • Originally there was a static dispatch mechanism. You’d just manually select the active connection from a list of connections and all operations would be routed to it. This approach was simple and effective, but required you to constantly keep track of whether you’re using the right connection. This problem was further compounded by the creation of ClojureScript.

  • Eventually we introduced the concept of dynamic dispatch, where we’d use a combination of the filename extension and the project directory to figure out where to send operations. This approach worked reasonably well, but was problematic when you had multiple connections of the same type for the same project. There was also no logical grouping of related connections.

  • This brings us to the present - today’s approach to managing multiple connections is an evolution of the dynamic dispatch. Related connections are grouped together in sessions, which are tied to some context (typically a project directory). If some operation dispatch is ambiguous it will fail with an error message. You can manually link (attach) buffers, files and directories to sessions in such situations.

In the following sections we’ll go over the basic terminology with respect to connection management, and we’ll cover the typical scenarios you’d normally have to deal with. The topic might seem a bit intimidating, but it’s actually fairly straightforward once you get to know the terminology and wrap your head around the basic idea.

Sessions

In the context of this section "session" stands for a group of nREPL connections. That should not be confused with nREPL’s own notion of a session (each nREPL connection can be segregated into multiple sessions).

CIDER maintains a grouped view of opened nREPL connections through Sesman sessions. Each session is a collection of connections which share the same nREPL server. You can, however, have multiple sessions sharing the same nREPL server (although you’re unlikely to ever need this).

Starting New Sessions

You can start new sessions with the following commands:

  • C-c C-x j j (cider-jack-in-clj)

  • C-c C-x j s (cider-jack-in-cljs)

  • C-c C-x j m (cider-jack-in-clj&cljs)

  • C-c C-x c j (cider-connect-clj)

  • C-c C-x c s (cider-connect-cljs)

  • C-c C-x c m (cider-connect-clj&cljs)

If a command creates multiple REPLs (e.g. cider-jack-in-clj&cljs) they are going to be added to the same session.

You’ll normally get a warning if you try to create a new session for some project if there’s already an existing session for it (e.g. after running cider-jack-in-cljs after cider-jack-in-clj for the same project). Generally in such cases it’s preferred to use commands that can add more REPLs to the existing session. We’ll cover those in the next section.

Adding REPLs to a Session

You can add new REPLs to the current session with:

  • C-c C-x s j (cider-connect-sibling-clj)

  • C-c C-x s s (cider-connect-sibling-cljs)

A very common use-case would be to run cider-jack-in-clj for some project and then follow up with cider-connect-sibling-cljs.

Unless there are both Clojure and ClojureScript REPLs in the same session smart-dispatch commands (e.g. evaluate the code in the right Clojure/ClojureScript REPL, toggle between Clojure and ClojureScript REPL) won’t work. A very common problem newcomers experience is to create a Clojure REPL and a ClojureScript REPL in separate sessions and wonder why those are not interacting properly with one another.

In the case of using separate config files for the clj and cljs dependencies (e.g. clj dependencies in deps.edn and cljs dependencies in shadow-cljs.edn) it is currently impossible to group those two repls in the same session. However, this can be worked around with cider-merge-sessions - see Combining REPLs Split Across Sessions.

Session Life-Cycle Management

Session life-cycle management commands live on the Sesman keymap (C-c C-s)

  • C-c C-s s (sesman-start)

  • C-c C-s r (sesman-restart)

  • C-c C-s q (sesman-quit)

The command sesman-start wraps around all of the aforementioned jack-in and connect commands. You can also invoke same functionality with M-x cider or C-c M-x.

To quit or restart individual connections use CIDER commands

  • C-c C-q (cider-quit)

  • C-c M-r (cider-restart)

Current Session

All CIDER commands (evaluation, completion, switching to REPL etc.) operate on the relevant REPL within the current session. The current session is the most relevant session among all linked sessions (or friendly sessions when no links exist). Session relevance is decided by the specificity of the linked contexts and recency of the REPL buffers.

If the current context is linked to a single session then that session is the current one. If multiple sessions are linked to a context (say, a project) then the current session is the one containing the most recently viewed REPL.

Links to more specific contexts have precedence. For example, if you have two sessions linked to the same project and another to a directory within that project, then the session linked to the directory is the current session. Thus, again, there is no ambiguity.

By default Sesman allows multiple simultaneous links to projects and directories, but only one link per buffer. See sesman-single-link-contexts if you would like to change that.

Default Session

If you’d rather bypass sesman’s context-based session inference and always use a specific session, you can designate one as the default session. When a default session is set, all REPL lookups (evaluation, completion, etc.) use it regardless of project context. This is useful for monorepo setups, scratch buffers, or when working across multiple projects that share a single REPL.

  • cider-set-default-session — prompts you to pick from the active sessions and sets it as the default.

  • cider-clear-default-session — clears the default session, reverting to normal project-based session association.

Both commands are also available from the CIDER menu.

If the default session no longer exists (e.g. it was closed), CIDER will warn you and fall through to the normal session lookup.

Current REPL

The current REPL is the most relevant REPL from the current session. REPL relevance is determined by the type of the current buffer. For example if the current buffer is a clj buffer then a clj REPL is selected. Ambiguous situations could arise when, for instance, there are multiple clj REPLs within a session, or the current buffer is a cljc buffer and both clj and cljs REPLs exist in the session. In such cases the current REPL is the most recently viewed REPL of the relevant type.

Switch to the current REPL buffer with C-c C-z. You can then use the same key combination to switch back to the Clojure(Script) buffer that you came from.

The single prefix C-u C-c C-z, will switch to the current REPL buffer and set the namespace in that buffer based on namespace in the current Clojure(Script) buffer.

Dispatching from .cljc Files

.cljc code is potentially valid in both Clojure and ClojureScript, so when a session has both a clj and a cljs REPL, CIDER can’t infer a single destination from the file type alone. The behavior is controlled by cider-clojurec-eval-destination:

  • multi (the default) - dispatch to both the clj and cljs REPLs of the current session at once. This matches how .cljc code is actually loaded by both runtimes, so you see results from each.

  • clj - always dispatch to the Clojure REPL.

  • cljs - always dispatch to the ClojureScript REPL.

If the session only has one of the two REPL types, that one is used regardless of the setting; the missing half is simply skipped until a matching REPL joins the session.

Sessions can be linked to contexts (projects, directories and buffers)

  • C-c C-s b (sesman-link-with-buffer)

  • C-c C-s d (sesman-link-with-directory)

  • C-c C-s p (sesman-link-with-project)

  • C-c C-s u (sesman-unlink)

Typically you’ll want to invoke those commands in file buffers and occasionally is some special buffers (e.g. a scratch buffer). You should never run them in a REPL buffer, as a REPL is an integral part of a session.

Friendly Sessions

Sesman defines "friendly" sessions to allow for on-the-fly operation on sessions from contexts where there are no explicit links. In CIDER a session is friendly to a buffer when the buffer’s file lives under the session’s project directory. So if you open a file anywhere in your project, the project’s session is automatically used even before you link anything explicitly. Explicitly linked sessions still have precedence over friendly ones.

Files that live outside the project directory don’t match this rule. The most common case is jumping to a dependency’s source with cider-find-var (M-.): there CIDER pins the buffer to the session you navigated from, so evaluation and other commands keep targeting that REPL. Source buffers you open by other means (e.g. a plain find-file into a jar) won’t be associated automatically; link a session explicitly or set cider-default-session if you need that.

Earlier CIDER versions inferred friendly sessions from the full project classpath (and, as a fallback, the buffer’s namespace). That ran on every redisplay and could cause severe editor lag, so it was replaced with the simpler project-directory rule described above.

You can disable friendly session inference by customizing sesman-use-friendly-sessions.

Handling Trickier Situations

The defaults work well for the common case of one project with one or two REPLs. This section walks through the situations where dispatch gets ambiguous and what you can do about them. The recurring theme: when CIDER can’t infer the right session on its own, you make the relationship explicit with a context link or a default session.

Working on Multiple Projects at Once

Having sessions for several projects open simultaneously is fully supported. Each project’s buffers resolve to that project’s session through friendly matching (the file lives under the project directory), so simply switching between buffers switches the current REPL along with them. No manual bookkeeping is required as long as the projects live in separate directories.

The wrinkle to be aware of is shared code. If you jump from project A into a dependency whose source you also happen to have open as part of project B, the buffer can only point at one session at a time - see Editing Dependency Sources below.

Evaluating Code Outside a Project

If you try to evaluate code in a buffer that doesn’t belong to any project (and isn’t otherwise linked), CIDER has nothing to dispatch to and you’ll get a No linked CIDER sessions error. This commonly happens with standalone scripts, files opened outside any project directory, or a REPL started before you opened the file.

You have a few options:

  • Link the buffer to a session explicitly with C-c C-s b (sesman-link-with-buffer), or link its directory with C-c C-s d.

  • Set a default session so every unlinked buffer falls back to it. This is the most convenient option when you routinely evaluate throwaway code against a particular REPL.

  • Start a REPL for the project the file belongs to.

Editing Dependency Sources

When you navigate to a definition outside your project - typically a dependency’s source via cider-find-var (M-.) - CIDER pins that buffer to the session you navigated from, so evaluation and lookups there keep targeting the REPL you came from.

Two consequences are worth knowing:

  • The pin takes precedence over context links and friendly matching for that buffer. If you want a pinned dependency buffer to follow a different session, navigate to it again (e.g. another M-.) from a buffer belonging to that other session; revisiting re-pins it to the new origin.

  • If the pinned REPL is later killed, the pin is ignored and the buffer falls back to normal session resolution.

Source buffers you open by other means (a plain find-file into a jar, a bookmark, etc.) are not pinned, because CIDER never saw which REPL they relate to. Link them explicitly or rely on a default session.

Multiple REPLs of the Same Type in One Session

When a session has more than one REPL of the relevant type (say, two clj REPLs), CIDER dispatches to the most recently viewed one. That’s usually what you want, but it makes the target depend on your buffer history, which can be surprising.

To pin dispatch to a specific REPL deterministically, link the source buffer (or its directory) to the session and use the sesman-browser (C-c C-s w) to keep track of which REPL is which. If the REPLs really belong to distinct contexts, consider putting them in separate sessions instead.

Combining REPLs Split Across Sessions

Sometimes related REPLs end up in separate sessions even though you’d like them treated as one - most commonly when a project’s clj and cljs dependencies live in different config files (e.g. deps.edn and shadow-cljs.edn) and can’t be jacked in together. cider-merge-sessions papers over this:

  • host merges all sessions for the project that share the same host.

  • project merges all sessions linked to the project.

With merging on, smart-dispatch (including .cljc multi evaluation and clj/cljs toggling) sees the REPLs as a single pool. The trade-off is that merging widens the set of candidate REPLs, so if you have genuinely unrelated REPLs you may reintroduce the same-type ambiguity described above.

Displaying Session Info

Get info on all linked and friendly sessions in the current context with C-c C-s i (sesman-info). On C-u, display info on all CIDER sessions. For the connection specific information use CIDER’s built-in cider-describe-connection (C-c M-d).

An interactive view of all CIDER sessions is available through the sesman-browser (C-c C-s w).

For lower-level nREPL details there are two more commands:

  • cider-describe-nrepl-session prompts for one of the connection’s nREPL sessions and shows its type and the ops it supports.

  • cider-list-nrepl-middleware lists the nREPL middleware currently loaded in the connection.

Customizing Session and REPL Names

By default session names consist of abbreviated project name, host and port (e.g. project/dir:localhost:1234). REPL buffer name consist of the session name and the REPL type specification post-fix (e.g. *project/dir:localhost:1234(cljs:node)*).

You can customize session names with cider-session-name-template and REPL names with nrepl-repl-buffer-name-template. See also cider-format-connection-params for available formats.

Reusing dead REPLs

Under normal circumstances, CIDER automatically kills the REPL buffers and cleans up after itself when ending a session. However, when a session is terminated unexpectedly, e.g. when it crashes or is disconnected from an external server process, the REPL buffer is left without an active connection and outputs a log:

*** Closed on < date/time > ***

Upon starting a new connection, CIDER can detect these "dead REPLs" and offer to reuse the buffer for the new connection. By default, it prompts for confirmation whenever a dead REPL buffer is available for reuse, but you can customize this behavior via the variable cider-reuse-dead-repls. Setting it to auto reuses a dead REPL buffer automatically, and only displays a prompt when there are multiple options to choose from. To suppress the prompt entirely, set it to nil to always start a new REPL buffer, or any to reuse the most relevant dead REPL.