When I start learning a new language I like to begin by understanding the tooling ecosystem. For me, having a handle on the tools enables me to confidently focus on learning the language itself. For example, when I came to Clojure my questions went something like this:

How do I install Clojure?

Clojure? How do I run a Clojure program?

a Clojure program? How do I manage Clojure packages (dependencies)?

Clojure packages (dependencies)? How do I configure a Clojure project?

a Clojure project? How do I build Clojure for production?

Now, when I first came to clojure, the answer to the above questions were, "use lein or boot". Then, around the end of 2017, a third option came along: the Clojure CLI Tools . Admitedly, it took me a while to understand their purpose and how to use them and that's where this post comes in

My goal with this post is to share my knowledge around the Clojure CLI Tools by outlining the problem they solve and how they compare to other tools like lein and boot .

If you installed Clojure using the official guide you likely already have the Clojure CLI Tools installed are are using them. Having said this, the Clojure CLI Tools can go by a number of names, and people often refer to the sub-tools within the Clojure CLI Tools suite. Thus, before we go on, let's nail down some naming conventions.

Clojure CLI Tools is an umbrella name and may not even be the official one. It includes tools like clj , clojure , deps.edn and tools.deps.alpha . Thus, you will often here members of the Clojure community referring to each one of these individually. When they are, they are often (context is important here) referring to what I am calling the Clojure CLI Tools . For brevity, I will refer to them all as clj going forward.

Alright, so we have clj available to us, what does it do and how can we use it? Here are some common tasks:

Run a clojure repl

clj

Run a clojure repl program

clj -m your-clojure-program

manage Clojure dependencies

clj -Sdeps '{:deps {bidi {:mvn/version "2.1.6"}}}'

If we were to just look at the above commands, it appears that clj is doing many things. Now, it's okay to think about it like this, but I think it's also important to understand that clj itself is a suite of tools which includes:

clj/clojure - two separate bash script commands

deps.edn - an edn file

tools.deps.alpha - a clojure program

Once I understood the above, it became easier to follow along with conversations on forums like Clojurians and understanding the tool was more straightforward. The reason for this is because when the community discusses the clj tool it can seem that clj , deps.edn and tools.deps.alpha are used interchangeably. In truth, they are all separate things that are wrapped by the clj tool.

The next few sections will discuss each of the above tools in more detail and how they all come together.

clj is the interface to the suite of tools mentioned in the previous section. As mentioned, when you install the Clojure CLI tools you will have access to two commands: clj and clojure . They are just bash scripts and both commands, while separate, actually do the same thing under the hood:

java [ java-opt* ] -cp classpath clojure.main [ init-opt* ] [ main-opt ] [ arg* ]

But wait, if both clj and clojure do the same thing, why have two commands? Let's dig into this.

Calling the clj command will call the clojure command. The difference between the two is that when you call clj it wraps the clojure command with a tool called rlwrap and then calls clojure .

So why do this? They do this because rlwrap adds readline support to the clojure command. Translation: It makes it nicer to type in the Clojure REPL in the terminal. It's for this reason that you will be encouraged to use clj during development, where as clojure is more commonly used in a CI or production setting.

So to recap, the only thing that the clj tool does is:

run clojure programs

Provides a standard way to interact with clojure programs

Improves the "Getting Started" story

But as we mentioned, it will call out to tools.deps.alpha to help resolve dependencies.

tools.deps.alpha builds a classpath and resolves dependencies. The longer way of explaining what it does is:

reads in dependencies from a deps.edn file

file resolves the dependencies and their transitive dependencies

builds a classpath

Note that NEITHER clj or tools.deps.alpha are "building" clojure artifacts.

Aside from the above, the best thing you can do to learn more is listen to Alex Miller, the author of tools.deps.alpha , speak about it on Clojure Weekly Podcast.

Finally, as I mentioned tools.deps.alpha knows which dependencies to resolve because it reads in the deps.edn file.

deps.edn allows you to specify project dependencies and configurations.

This is just an edn file where edn is like Clojure's version of json .

If you're from the JavaScript community it can be helpful to think of this file as the equivalent of a package.json file

deps.edn is just a map which accepts specific keywords. Here is an example of some of the common keywords:

{ :deps { .. . } :paths [ .. . ] :aliases { .. . } }

This is the file where you define the libraries your project needs, shortcuts and where to find your projects code. Ultimately, it's just a map with some keys. Now, it might seem odd that I think of this as a separate "tool". The reason I do this is because this is just an edn map with well defined k/v pairs.

So what this means is that, in theory, you don't need to use tools.deps.alpha . Instead, you could build your own version of tools.deps.alpha which consumes the deps.edn file and has it's own way of resolving dependencies. I'm not encouraging this, i'm just explaining why I see it as standing on it's own.

"Clojure CLI Tools Installer" is a fancy way of referring to the brew tap used to install Clojure on mac and linux machines. As of February 2020, Clojure started maintaining their own brew tap. Thus, if you installed the clojure command line tools via

brew install clojure

you will likely want to uninstall clojure and install the following:

brew install clojure/tools/clojure

In all likelihood, you would probably be fine with brew install clojure . The thing is that while brew install clojure will still see some love, it won't be as consistent as clojure/tools/clojure tap.

clj v lein v boot

Let's end this conversation with a quick contextualization of clj , lein and boot .

I won't dive into the history, for this I recommend the blog post All the Paths by Sean Corfield.

The first point is that you will choose between one of the three tools ( clj , lein , or boot ) for your project. You don't use more than one. Just like you wouldn't use both boot and lein , you won't use both clj and boot or clj and lein . Furthermore, none of these tools should conflict with the other.

Now, when I said that you don't actually combine more than one of these tools, this is not 100% true. Take for example the fact that the "build" story for clj is not as "easy" as lein which has led to examples of clj calling to lein just for the production builds of ones apps

If you're curious which to choose, I think it's obvious that I would suggest clj . The reason I like clj is because the tool is simple and easy to use. You can read through clj and tools.deps.alpha in an afternoon and understand what they are doing if you had to. If the same occurs with lein or boot , you will not have any such luck.

Secondly, and most importantly, the Clojure community is really leaning into building tools for clj . For example, where lein used to have significantly more functionality, the community has built a ton of incredible tools that will cover many of your essential requirements. There is also the fact that deps.edn is easier to configure because there are less configuration options and less need to understand what lein is doing as you want to perform more advanced configurations.

Finally, when it comes to managing your project configurations and building out maintainable organizational structures (monorepo) it doesn't get easier than clj

So yes, clj for the win.