How do you use nREPL?

I realize this might be an overly general question, but I was wondering how people use nREPL. I mean, what are you using it for? I’m basically looking for inspiration, so to speak :slight_smile:

Here is how I am using it at the moment.

I have a Debian server where I installed Babashka. It’s on GCP Compute Engine and I installed Tailscale on it, so it’s super convenient to connect to it via SSH without having to manage SSH keypairs. Sometimes I access my server and launch the nREPL server integrated in Babashka:

bb --nrepl-server 1667

I then create an SSH tunnel between the Debian server and my laptop…

ssh -L 1668:localhost:1667 giacomo@debian-vm

…and connect to the nREPL server with Calva (by selecting Connect to a running REPL server, not in your project).

I have a couple of babashka scripts that I evaluate in VS Code + Calva and send to the nREPL server, but apart from that, I don’t use nREPL that much. Do you use nREPL for other tasks? What am I missing out?

Also, do you keep the nREPL server running? I saw that the memory consumption is quite low, and I don’t think it would be a security issue that big to always keep it up, since my Debian server is only accessible via SSH with publickey authentication.

And lastly, how can I use nREPL in a cloud environment? For example, I initially thought about creating a container image with babashka installed in it, expose a port for the nREPL server, and connect to the nREPL server from Calva. But now I don’t think it’s feasible, since you tipically can use only one port with a Container as a Service like GCP Cloud Run.

If you have cool use cases, talks, blog posts to recommend, I’m all ears. Thanks!

1 Like

I wrote an IRC bot a couple of years ago. One essential thing about IRC is that it’s a synchronous protocol, so timing is everything. But that also means it’s really cumbersome to have to stop and start the program to inspect its state. With nREPL, I could initialize the program state in a Clojure Var, stop and restart instances at will, change configuration and inspect the state, all whilst the IRC bot was running. nREPL is like a turbocharged debugger, because it’s not just relegated to observing the program and maybe poking at it from outside.

With more modern, asynchronous protocols you can get a lot of mileage out of microservice-style applications, where it’s fine to debug the protocol manually because each individual connection is short-lived and, ideally, idempotent. Even there, though, interactively experimenting with changes is more comfortable with nREPL.

When it comes to production deployment, though, I don’t keep the nREPL running. I think that’s antithetical to the idea of immutable deployments - not that mutable programs are inherently bad, but simply that it’s difficult to coordinate that with multiple people, or even keep track of yourself as the weeks or months pass.

1 Like

Locally I use it for a bunch of things:

  • running tests
  • exploration in a scratch buffer and evaluating forms
  • starting/stopping dev system to start the backend API when working on the UI

In production/cloud, nREPL is incredibly powerful and can be a foot gun, that said - I used it for a lot of things

  • running one-off data migrations (that were authored as a loadable file before hand)
  • debugging production issues, particularly around service<->service communication, when logs, metrics and error reports do not provide enough information sometimes - in particular when working with APIs provided by vendors
  • very, very, very rarely when given application had only one instance running I did hotpatch some code, but only as a temporary measure until the real fix was rolled out shortly after

It’s very important if you got that route that you have sufficient access controls in place, as RCE doesn’t even describe it if somebody figures out your REPL is wide open

1 Like