A Brief Beginner's Guide To Clojure
← prev | next →     Top-level ToC     /libs-management-and-use.html     (printable version)

Clojure programs typically rely on external libraries in order to run. If you’re writing such a Clojure program, your users would of course need to have these libraries available in order to run your program.

Clojure libraries may make use of and rely on other libraries. If you’re writing such a Clojure library, other programmers who would like to use your library would need some way to install it as well as install any other libs that yours depends upon.

The way these issues are handled with Clojure is:

  1. A Clojure application is typically distributed as a jar file which includes all of the app’s dependencies, including the Clojure jar itself.

  2. A Clojure library is distributed by itself as a jar file. In practice, libraries are available at and automatically fetched as needed from Clojars or Maven Central (or some other repository) by the Leiningen tool (see below), which also recursively fetches any dependencies.

1 Leiningen

As discussed briefly in the dev environment chapter, the tool most commonly used for managing your Clojure projects is called “Leiningen”. Lein automates a number of project-related tasks. It can:

  • create new projects
  • fetch dependencies for your project (storing them in your ~/.m2 dir)
  • build and run your project’s code
  • run your project’s tests
  • start a Clojure REPL (either specifically for your project or else not associated with any project in particular)
  • package your project as a jar (whether it’s a library or an app)
  • show you your project’s classpath
  • generate a maven-style “pom” file for your project
  • package and upload your library projects to Clojars

There’s also a number of available plug-ins that extend lein to support additional commands/tasks.

The Leiningen readme and tutorial explain the details of installing and using lein. A few comments I’d add:

  • lein is a standalone program (a shell script which fetches and uses the lein jar, which it installs into ~/.lein/self-installs). You quite often run lein from inside a project directory.

  • When you create a new project (ex. lein new my-lib), lein starts you off by creating a “project.clj” file in your newly-created project directory. This is the project-specific “config file” that lein uses to manage your project.

  • When you install lein, it creates ~/.lein and ~/.m2/repository directories for its own use. The ~/.m2/repository dir is used for caching jars which lein fetches for use by your projects, and the lein documentation refers to that dir as “the local repository”.

  • The lein tutorial mentions Ant and Maven. These are Java-land tools for building Java projects (recall, Java files also get compiled to Java bytecode). Lein actually uses the Maven library under the hood. Managing your Clojure projects may entail compiling/ahead-of-time-compiling Clojure (and possibly even Java) code, or making use of Java libraries … and lein automatically manages all of this for you.

  • The Leiningen github project contains a large sample project.clj file which you may find informative when looking for details on using a particular :option in your project.clj.

  • Some quick notes on a few of the lein tasks/commands (see lein help for the list of all of them):

    lein install
    is for installing a lib you’re developing into your own ~/.m2/repository, such that some other project you’re developing — which depends upon this lib — can use it even though it hasn’t yet been made available at Clojars.
    lein deps
    causes lein to download your project’s dependencies, though, you should never need to run this command explicitly (except for viewing the dependency tree), as lein takes care of it for you automatically.
    lein search
    If you use this command, it will take a while to run the first time (since it must download the rather large search index). I recommend instead using the Clojars/Maven-Central search forms.

    In addition to lein deps, you should also never need to explicitly run the compile or javac tasks. Lein will take care of running them automatically, if necessary.

2 Finding the Libraries You Want

If you don’t see what you need in clojure.core, the standard library, or contrib, have a look at the Clojure Toolbox.

And, of course, don’t be afraid to ask for recommendations on IRC or the Clojure mailing list.

3 Library Identification

If you’ve found a library you wish to use in your project, unless it’s in the Clojure standard library you’ll need to edit your project.clj file and add it to the :dependencies there so that lein knows your project depends upon it (and will download it for you). The format for specifying a library dependency looks like this:

    [group-id/artifact-id version-string]

and is sometimes referred to as the “coordinates” of the library.

The group-id indicates who’s associated with that particular library. The artifact-id is the library name. The group-id is optional if it’s the same as the artifact-id (and this is in fact quite common). The version string follows the common “major.minor.patch” pattern (ex. “1.0.2”; see semantic versioning).

Here are some examples of project coordinates:

[org.clojure/clojure "1.8.0"]
[org.clojure/java.jdbc "0.6.1"]
[sonian/carica "1.0.0"]
[clj-time "0.4.4"]
[environ "0.3.0"]

The convention for most libs at Clojars (the canonical ones that you’ll usually be using) is to have the group-id be the same as the artifact-id. And in that case, the group-id is omitted from the coordinates.

If you see a project at clojars with a group-id like “org.clojars.username”, it usually indicates that the project is a forked version of the canonical one.

3.1 A Note on Names

There are four names associated with a given library:

  • Its artifact-id. This is at the top of the library’s project.clj file, first argument to “defproject” (sometimes also preceeded by a group-id then a slash). It’s the “name” of the library.

    To use a library, you need its artifact-id (and group-id, if it differs) in your project.clj :dependencies.

  • Its group-id. This is optionally at the top of the library’s project.clj file, part of the first argument to “defproject” (before the artifact-id and separated from it by a slash). If only an artifact-id is present (no slash), that means the group-id is the same as the artifact-id. Might be the same as the github username.

  • Its github project name. Most Clojure lib repos are hosted at github, and most of those github projects are named the same as their artifact-id (though this isn’t required). The url for its github project page should usually be used for the project.clj defproject :url.

  • The namespace(s) it provides. A given library’s source code files will each contain an ns macro at the top, the first argument of which is the namespace that file provides. The namespace name mirrors the directory structure (for example, my-proj’s my-proj.core namespace is represented by my-proj/src/my_proj/core.clj).

    When using a library, in your source code file where you’d like to use it, you :require one or more of the namespaces it provides.

3.1.1 Some Conventions

For standard and contrib Clojure libraries: the namespaces provided all start with “clojure.”. For contrib libs, the artifact-id and github project name are the same. (For the standard libs, there are of course no github project names or artifact-ids.)

For other libraries, which are part of an umbrella project: the typical pattern is: group-id == github org == umbrella project name. The namespace(s) provided may be group-id.artifact-id.*. The github project url is usually github.com/group-id/artifact-id.

For other libraries: the artifact-id, top-level namespace provided, and github project name are all often the same.

3.1.2 Additional Observations

  • Although a given library’s group-id might be the same as the github username the project is under (if it is indeed hosted at github), the group-id and github username are not necessarily related. They very often are though, for example:

    the library coordinates its github url
    [sonian/carica “1.0.0”] https://github.com/sonian/carica
    [clojurewerkz/spyglass “1.0.2”] https://github.com/clojurewerkz/spyglass
  • Note that Clojars page url paths follow the group-id/artifact-id pattern (and leaves out the group-id when it’s the same as the artifact-id).

4 Using Libraries

4.1 Using Standard Libraries

To use standard libraries in your code you don’t need to touch your project.clj file, since these libs already come with Clojure. Just edit your core.clj file. For example, you can use the clojure.string standard lib like this:

(ns my-proj.core
  (:require [clojure.string :as str]))

(defn -main
  "docstring goes here"
  [& args]
  (println (str/reverse "encoded secret!")))

(Note that we’re using “str” here as an alias for clojure.string to save ourselves some typing.)

4.2 Using Contrib Libraries

All the contrib libraries have project pages at github (under https://github.com/clojure), with artifacts (jars) hosted at Maven Central. To use a contrib lib — for example, java.jdbc — we first need to look up its coordinates (which will go into our project.clj). You can find its coordinates on the contrib lib’s github project page (in the README.md). If the info isn’t there, that’s a documentation bug.

Incidentally, if you’d like to see this contrib lib listed at Maven Central, visit there and search for “java.jdbc”. This will tell you that the group-id is “org.clojure”, the artifact-id is “java.jdbc”, and the latest version is “0.6.1” (or whatever the most recent version is).

Add those coordinates to your project.clj’s :dependencies list, for example:

(defproject my-proj "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [org.clojure/java.jdbc "0.6.1"]]
  :main my-proj.core)

and make your core.clj’s ns macro look like:

(ns my-proj.core
  (:require [clojure.java.jdbc :as j]))

(Note that we’re using “j” here as an alias for clojure.java.jdbc to save ourselves some typing.)

4.3 Using Libraries from Clojars

If you’ve found a library you’re interested in at Clojars, the Clojars page for the lib should show you exactly what you need to add to your project.clj’s :dependencies list (it shows info on the most-recently released version).

As noted above: for canonical 3rd-party libs at Clojars, it’s common for the group-id to be the same as the artifact-id, and so there would be no group-id in the coordinates string you add to your project.clj.

In your core.clj file, you’ll often put something like “(:require [lib-name.core :as foo])” into your ns macro (where “foo” is some well-chosen short name), and then later use a function from that library like so: (foo/func-name ...).

The Clojars page for the lib should also contain a link to the github (or other home) page for the library, which in turn should contain a README showing some example usage. If there is no such link, consider searching for the lib at github and then filing a bug report at the lib’s project page about the issue.

4.3.1 Manually downloading jars from Clojars

If you want to directly download jar files from Clojars, look in http://clojars.org/repo/.

4.4 Using Various Java Libraries

Search Maven Central for the library you’re interested in, and adjust your project.clj’s :dependencies according to the GroupID, ArtifactID, and Latest Version info shown in the search results. In your ns macro you’ll use whatever namespaces you need which the library provides.

As for using Java libs which are not registered at Maven Central, see the lein repeatability doc’s “Free-Floating Jars” section.

5 Viewing the Dependency Tree

For a given project, to see the which libraries depend upon which, print out the dependency tree like so:

lein deps :tree

6 Keeping Dependencies up to date

To check if there are newer versions available of your project’s various dependencies, use the lein-ancient lein plug-in. Instructions for use are in its README.