Clojure Leiningen Tutorial

By Xah Lee. Date: . Last updated: .

Leiningen is a command line tool to automate things when working with Clojure. If you work with Clojure in real world projects, then Leiningen is necessary.

Leiningen home page is

This tutorial is for people who have never done Java or Clojure before. I tell you why you need to use leiningen, how to use it, and many things you need to know in using it.

lein repl 2016-03-06
lein repl screen. (running inside emacs eshell)

Why is Leiningen Needed?

Leiningen is basically necessary because:

What Does Leiningen Do?

Leiningen is a command-line tool that does many things. The most important are:

Install Leiningen

  1. Download the lein script at (or on Windows lein.bat at )
  2. Place it on your $PATH where your shell can find it (For example, at ~/bin)
  3. Set it to be executable (That is, run chmod a+x ~/bin/lein)
  4. Run it in terminal (type lein) and it will download and self-install.

How to add to bash $PATH?

Here's a example of how to add lein to your path.

Suppose you have lein script at ~/bin/lein.

Add the following to your bash profile ~/.bashrc:


After that, open a new terminal window or source ~/.bashrc.

Where is Leiningen installed?

lein is just a bash script. You can place it anywhere. I put it at ~/apps/lein/lein.

After you run it, it'll download stuff at ~/.lein/

It'll basically just download this jar file leiningen-2.6.1-standalone.jar. (The file size is 16M.)

Leiningen is basically a combination of the lein shell script and Java. The shell script is a frontend. The meat is the jar file. It is written in Clojure, running on JVM (Java Virtual Machine).

What is a jar file?

Jar file is a archived file of Java. It is how Java software are distributed. Typically, you start a Java app by java name.jar.

Jar file is a bunch of compiled Java class files of a directory, plus some extra info (such as which class file is the entry point.) (Java software is a set of compiled class files.)

When working with Clojure, you need to be familiar with Java tools and its package system, sooner or later. Bookmark the following to read later:

What is uber-jar?

“Uber jar” means jar file that contains all libraries a app needs. So, user just need this one single jar file to run the app. (as opposed to, needing to download other jar files and put them in class path.)

lein can create uber jar file for your project.

What is Ant? What's Maven?

They are build tools in the Java world. (similar to unix make).

See: What is Apache Ant, Apache Maven, What's the Difference?

Java world has a lib repository called Maven Central (or just Central) at

Because Clojure runs on JVM (Java Virtual Machine), so Clojure files are also compiled into class files, and is also packaged into jar files.

lein has features to help upload Clojure lib to Maven.

Leiningen Help

$ lein help
Leiningen is a tool for working with Clojure projects.

Several tasks are available:
change              Rewrite project.clj by applying a function.
check               Check syntax and warn on reflection.
classpath           Print the classpath of the current project.
clean               Remove all files from project's target-path.
compile             Compile Clojure source into .class files.
deploy              Build and deploy jar to remote repository.
deps                Download all dependencies.
do                  Higher-order task to perform other tasks in succession.
help                Display a list of tasks or help for a given task.
install             Install the current project to the local repository.
jar                 Package up all the project's files into a jar file.
javac               Compile Java source files.
new                 Generate project scaffolding based on a template.
plugin              DEPRECATED. Please use the :user profile instead.
pom                 Write a pom.xml file to disk for Maven interoperability.
release             Perform :release-tasks.
repl                Start a repl session either with the current project or standalone.
retest              Run only the test namespaces which failed last time around.
run                 Run a -main function with optional command-line arguments.
search              Search remote maven repositories for matching jars.
show-profiles       List all available profiles or display one if given an argument.
test                Run the project's tests.
trampoline          Run a task without nesting the project's JVM inside Leiningen's.
uberjar             Package up the project files and dependencies into a jar file.
update-in           Perform arbitrary transformations on your project map.
upgrade             Upgrade Leiningen to specified version or latest stable.
vcs                 Interact with the version control system.
version             Print version for Leiningen and the current JVM.
with-profile        Apply the given task with the profile(s) specified.

Run `lein help $TASK` for details.

Global Options:
  -o             Run a task offline.
  -U             Run a task after forcing update of snapshots.
  -h, --help     Print this help or help for a specific task.
  -v, --version  Print Leiningen's version.

See also: readme, faq, tutorial, news, sample, profiles, deploying, gpg,
mixed-source, templates, and copying.

Most Useful Lein Commands

The most basic useful commands are:

lein repl
Starts a server based Clojure REPL. You can use this instead of the standard Clojure REPL. (this allows you to have other tools such as emacs to connect to it. And also automate loading all dependent libraries of your project.)
lein new app name
Creates a new empty project. That is, creates a directory structure named name at current dir . (dir structure is necessary, because compiled language need source, target, dependency list, etc.)
lein run
Run your Clojure app. By default, it runs the file project_name/src/project_name/core.clj

First Lein Session: lein repl

First thing to try is to run lein repl in terminal.

lein repl 2016-03-06
lein repl screen. (running inside emacs eshell)

What is the difference between Clojure REPL and Leiningen REPL?

lein repl has many advantages:

Leiningen: You Must Have a Project

Most Leiningen commands make sense only if you have a project.

What is a “project”? What does it mean exactly?

A project is just a directory, usually with some subdirectory that has conventional meaning. For example: source code directory src, compiled file directory target, dependencies (libs) directory, etc.

These are necessary because Clojure is a hosted language on JVM. Java is a compiled language. Compiled languages typically need source directory, destination directory, dependency directory, etc.

Using lein means working with a project, because lein is about building, compiling, libraries dependency management, etc.

Even if you are just learning Clojure or Leiningen and don't really have a project, you must create a project to use or study lein. Because, almost everything assumes the current project, even a empty one.

Leiningen: Create a Project

So, first thing to do to use lein, is to create a project, by:

lein new app xtest
Creates a new “empty” directory structure (named xtest) at current dir.
◆ lein new app xtest
Generating a project called xtest based on the 'app' template.

it'll create a directory structure like this:

Here's what the directory and files mean:
dummy markdown file for project change log/notice.
directory for your project's documentation.
dummy file for git ignore pattern.
dummy file for mercurial ignore pattern.
dummy file your project's copyright etc info.
important. lein config file for this project.
description of the project.
libraries, misc files from everything else.
important. Your Clojure source code go here.
compiled Clojure/Java files. (this dir will be created when you compile.)
directory for unit testing code.

Lein Project Config File: project.clj

The file project.clj is the most important lein file. The files tells lein about your project dependencies, and other info lein needs to do its job.

Here's a default project.clj:

(defproject xtest "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url ""
  :license {:name "Eclipse Public License"
            :url ""}
  :dependencies [[org.clojure/clojure "1.8.0"]]
  :main ^:skip-aot xtest.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})

This file content is actually Clojure code. It's calling the function defproject. The defproject function is defined in Leiningen.

Most of the arguments are :key value pairs.

Here's some of the most important keys:

:main is the entry point of your project. Value is a Clojure namespace. (that is, when lein run, the function named -main of this key's value (a namespace) will be called.) The ^:skip-aot is a Clojure metadata syntax shortcut. [see Clojure: Metadata] This metadata in lein means don't do ahead-of-time compilation. See project.clj full doc at [2014-12-25 ]

:dependencies is libraries your project depends on. Because Clojure language is running on top of JVM, so we need clojure itself [org.clojure/clojure "1.8.0"], at least.

The value is a nested vector. Each element is of the form group_id/artifact_id "version"

What is “artifact” id? what's group id?

A file in the Java Maven repository is called “artifact”, and it has a id.

It also have a group id, usually a reverse domain name.

And it has a version string.

Maven files has a associated config file in XML format, called POM (“Project Object Model”), as “pom.xml”. [ ]

The {artifactId, groupId, version} are from the “pom.xml”

For example, if you have a Maven project, and you want to declare the lib [2014-11-10 ] as dependency, you can add this content to your pom.xml:


In Leiningen's “project.clj” file syntax, this would be:

:dependencies [[org.clojure/tools.nrepl "0.2.5"]]

Note: the following is a convention, but not guaranteed:

:target-path is where the compiled files (java class files) will go.

:profiles is basically some preferences.

Global Location of Compiled Java Files

Keep in mind that, leiningen will generate many compiled java files at ~/.m2/. (That directory is the default directory used by Maven. Leiningen follows the convention.)