If you’re happy using lein
, you might as well continue to do so.
If you’re using Emacs/CIDER, I’m pretty sure the latest version knows how to start an nREPL using the CLI/deps.edn
.
As for why you might want to switch:
-
lein
generally starts two JVMs: one for itself and one for your program –clj
/clojure
uses a JVM to compute the classpath but then caches it so subsequent uses ofclj
/clojure
run only one JVM (with the same set of aliases/dependencies) -
lein
relies on the Maven/Aether/Pomegranate resolution algorithm for picking library versions if your dependencies bring in a conflict and that can be the source of weird problems that then drive people intolein deps :tree
and “pedantic” mode; CLI/deps.edn
uses a simpler algorithm that favors explicit dependencies and more recent versions, which causes fewer surprises and is more easily controlled - CLI/
deps.edn
can easily bring in dependencies from local source installations as well as from anygit
repo (by URL and SHA);lein
can do this too but requires plugins and/or more futzing around in yourproject.clj
file -
lein
always runs with “everything” out of the box; CLI/deps.edn
runs with just the tooling you tell it to use so it’s often faster to start up (even aside from the two vs one JVMs issue above)
We originally switched from lein
to boot
back in 2015 because we wanted a) better programmability and b) easier support of a monorepo with lots of subprojects. boot
served those needs very well but we started to run into performance issues with the fileset abstraction and bugs with the pod refresh stuff so we were happy to switch to the CLI/deps.edn
in 2018 – our custom boot
tasks became simple scripts that could easily be run via clojure
and performance was good.
My main reason to prefer CLI/deps.edn
is “simple tools”. I’m with Stu Halloway and Eric Normand and others on wanting my dev tooling to be as simple and lightweight as possible: small, composable tools, with no “magic”. That’s also why I don’t use nREPL any more, I don’t use CIDER or Compliment, I just use a plain Socket REPL. That means I can fire up any Clojure process (or even a legacy app that includes Clojure) and have it start a Socket REPL with just a JVM option, which means dev, test, and production can all expose the exact same interface: a Socket REPL that is built into Clojure itself. That in turn means that I can use the exact same dev tooling with local processes and with remote processes.