Leiningen, a project by Phil Hagelberg , has become one of the most contributed to Clojure projects, and also one of the most used.
UPDATE (2013-12-12): I highly recommend going through the official community-maintained tutorial instead of this blog, which is essentially unmaintained.
This introduction will focus on Leiningen itself, rather than the motivations for using it or about the way it differs from other tools. For some discussion of those differences, see the mailing list discussions on the Clojure
project.clj spec, or this StackOverflow question.
For the purposes of this tutorial, just know that Leiningen is, as its tagline states, "A build tool for Clojure designed to not set your hair on fire".
This tutorial is intended for people who have never touched Leiningen—if you’ve used it on a project before, you’re better off jumping straight to the resources I mention at the end of this post, such as the excellent documentation in the project itself.
There are only a few prerequisites for getting going with Leiningen:
leinscript for Unix/Mac OSX , or the zip file for Windows
- A Java runtime environment (at least version 1.5)
- An internet connection, which you’ll need in order to get Leiningen bootstrapped.
Once you’ve downloaded the
lein script (or, on Windows, downloaded the zip file and unzipped it), you’ll need to add it to your
PATH, and make sure it’s executable (just adding it to the
PATH should be enough for Windows):
I keep my lein script in
~/bin, as Phil suggests in the project
README. Now, if you just run…
…you’ll see some download activity as Leiningen grabs its latest stable-release jarfile and puts it into the
~/.lein/self-installs directory, where your
lein script will be able to find it later, as you get ready to run real tasks.
Trying it out
Let’s start out by creating a new project:
Now, if you
cd my-sandbox, you’ll find that Leiningen has created a directory structure for you, which is typical for Clojure projects:
The only file here that we need to concern ourselves with is the project.clj, which describes the project in several ways:
The first thing to notice is that this is just Clojure code. No yucky XML to deal with (I know, we shouldn’t dismiss XML out of hand), and things are very clean and minimal. Let’s break it down into parts:
defprojectis the macro that does the work to collect information about the project so that the Leiningen tasks know what to do.
my-sandboxis the name of our project, expressed here as a Clojure symbol.
"1.0.0-SNAPSHOT"is the project version, which will become important later.
The remainder of the entries are expressed in key-value pairs. It’s essentially a map, even though
defprojectuses unrolled arguments, so we don’t need the usual curly braces.
Leiningen’s dependency management is really one of the coolest things about it, so let’s take a look at the way you identify dependencies.
[GROUP/]ARTIFACT-ID VERSION is the syntax you use when declaring a dependency. When the
GROUP is the same as the
ARTIFACT-ID, so the normal syntax would give you something like
foobar/foobar "1.0.0", you can safely omit the
GROUP and say 5
foobar "1.0.0" instead.
The idea is that the
GROUP is whatever organization created the code, and the
ARTIFACT-ID is the name of the project or artifact itself—pretty intuitive. You’ll notice that our project name and version look suspiciously similar to those of our dependencies, and in fact we can also use the same
GROUP/ARTIFACT-ID syntax as the project name to specify that this project belongs in a group different from its name.
Each of the projects in our dependency list will declare its dependencies as well, through the
pom.xml file associated with that project. When we actually upload to a Maven repository (such as Clojars), we can use Leiningen to generate that
POM file for us, rather than hand-coding it.
Now that we have a little background on how the
project.clj is constructed, we can go ahead and pull down our dependencies with the following command (making sure we’re in the
And now you have
.jar files for your dependencies in a newly created
Easy, right? In the event that you do see errors, and in the interest of total disclosure, the dependencies are first downloaded into your
~/.m2/repository directory, then copied from there into your project’s
So if you encounter problems, you may want to check to see that you have reasonable permissions and ownership set up for that directory.
…should make it clear that Leiningen sets up your classpath in a reasonable way for your project: the
resources directories are all there, as are the jarfiles for your dependencies.
This is the classpath that most any Leiningen task will use when running from your project directory, and will obviously vary on a per-project basis. The upshot here is that you can fire up a REPL that already has all of your dependencies on the classpath, without resorting to any deprecated
Don’t forget that you’ll still need to
use the namespaces you want to use, as you would with any other Clojure libs besides the ones automatically provided in
clojure.core and the other automatically-available namespaces.
…shows you that the project starts with one failing test, which expects
false to be true—not one that I’m particularly keen to make pass, but a good example nonetheless.
It’s pretty trivial to run tests this way, but of course the JVM startup time makes it much more efficient to run tests in a different way:
Leiningen’s interactive mode is a pretty sweet way to avoid taking the JVM startup time hit for every test run, but it’s a bit of a double-edged sword: you might get falsely passing test runs, because of the fact that JVM classes will stick around in memory even after you delete their associated functions.
Just be sure to run tests occasionally outside of interactive mode, and you’ll be sure to catch errors like this quickly.
Leiningen is a mature and interesting enough project that there’s no way to cover it all in a single blog post. I hope that by this point I’ve whet your appetite a bit to learn more about Leiningen (and perhaps Clojure).
You’ll also get a lot out of joining (and searching) the Leiningen mailing list and asking questions in the #leiningen and/or #clojure IRC channels on FreeNode.
Seriously, if you haven’t visited the IRC channels, do that as soon as possible! Also, running…
…gives you an idea of all the things that are possible with the base distribution of Leiningen, and a growing plugin ecosystem has been springing up to support various users’ build, distribution, testing, and other needs.
Further, there are many opportunities to jump into the Leiningen code itself and make improvements. Phil frequently tags issues as suitable for newbies to jump in, which is great for people looking to get into doing open-source software in Clojure.