Language Guide: Clojure

Last updated
Tags Cloud Server v3.x Server v2.x

This guide will help you get started with a Clojure application on CircleCI. If you’re in a rush, just copy the sample configuration below into a .circleci/config.yml in your project’s root directory and start building.


Otherwise, we recommend reading our walkthrough for a detailed explanation of our configuration.

We’re going to make a few assumptions here:

  • You’re using clojure.test with Leiningen’s built-in test task.
  • Your application can be distributed as an all-in-one uberjar.

If you use another testing tool, you can just adjust that step to run a different lein task.

Sample configuration

version: 2
jobs: # basic units of work in a run
  build: # runs not using Workflows must have a `build` job as entry point
    working_directory: ~/cci-demo-clojure # directory where steps will run
    docker: # run the steps with Docker
      - image: cimg/clojure:1.10 # ...with this image as the primary container; this is where all `steps` will run
          username: mydockerhub-user
          password: $DOCKERHUB_PASSWORD  # context / project UI env-var reference
    environment: # environment variables for primary container
      LEIN_ROOT: nbd
      JVM_OPTS: -Xmx3200m # limit the maximum heap size to prevent out of memory errors
    steps: # commands that comprise the `build` job
      - checkout # check out source code to working directory
      - restore_cache: # restores saved cache if checksum hasn't changed since the last run
          key: cci-demo-clojure-{{ checksum "project.clj" }}
      - run: lein deps
      - save_cache: # generate and store cache in the .m2 directory using a key template
            - ~/.m2
          key: cci-demo-clojure-{{ checksum "project.clj" }}
      - run: lein do test, uberjar
      - store_artifacts: # Upload test summary for display in Artifacts:
          path: target/uberjar/cci-demo-clojure.jar
          destination: uberjar
      # See for deploy examples

Get the code

The configuration above is from a demo Clojure app, which you can access at

If you want to step through it yourself, you can fork the project on GitHub and download it to your machine. Go to the Projects dashboard in the CircleCI app and click the Follow Project button next to your project. Finally, delete everything in .circleci/config.yml.

Now we are ready to build a config.yml from scratch.

Config walkthrough

We always start with the version.

version: 2

Next, we have a jobs key. Each job represents a phase in your Build-Test-Deploy process. Our sample app only needs a build job, so everything else is going to live under that key.

In each job, we have the option of specifying a working_directory. In this sample config, we’ll name it after the project in our home directory.

version: 2
    working_directory: ~/cci-demo-clojure

This path will be used as the default working directory for the rest of the job unless otherwise specified.

Directly beneath working_directory, we can specify container images under a docker key.

version: 2
      - image: cimg/clojure:1.10
          username: mydockerhub-user
          password: $DOCKERHUB_PASSWORD  # context / project UI env-var reference

We use the CircleCI-provided Clojure image with the lein-2.7.1 tag.

We set JVM_OPTS here in order to limit the maximum heap size; otherwise we’ll run into out of memory errors. The standard container limit is 4 GB, but we leave some extra room for Leiningen itself as well as things the JVM keeps outside the heap. (You can avoid the Leiningen overhead by using lein trampoline ... in some cases.) If you have background containers for your database or queue, for example, consider those containers when you allocate memory for the main JVM heap.

Normally Leiningen expects to be run as a non-root user and will assume you’re running as root by accident. We set the LEIN_ROOT environment variable to indicate that it’s intentional in this case.

      JVM_OPTS: -Xmx3200m
      LEIN_ROOT: nbd

Now we’ll add several steps within the build job.

We start with checkout so we can operate on the codebase.

Next we pull down the cache, if present. If this is your first run, or if you’ve changed project.clj, this won’t do anything. We run lein deps next to pull down the project’s dependencies. Normally you never call this task directly since it’s done automatically when it’s needed, but calling it directly allows us to insert a save_cache step that will store the dependencies in order to speed things up for next time.

Then lein do test, uberjar runs the actual tests, and if they succeed, it creates an “uberjar” file containing the application source along with all its dependencies.

Finally we store the uberjar as an artifact using the store_artifacts step. From there this can be tied into a continuous deployment scheme of your choice.

      - checkout
      - restore_cache:
          key: cci-demo-clojure-{{ checksum "project.clj" }}
      - run: lein deps
      - save_cache:
            - ~/.m2
          key: cci-demo-clojure-{{ checksum "project.clj" }}
      - run: lein do test, uberjar
      - store_artifacts:
          path: target/cci-demo-clojure.jar
          destination: uberjar

Nice! You just set up CircleCI for a Clojure app.

See also

See the Deploy document for example deploy target configurations.

Detailed examples

The app described in this guide illustrates the simplest possible setup for a Clojure web app. Real-world projects tend to be more complex, so you may find this more detailed example useful as you configure your own projects:

  • Syme, a site which configures disposable virtual machines for remote collaboration (uses PostgreSQL, continuously deployed to Heroku)

Help make this document better

This guide, as well as the rest of our docs, are open source and available on GitHub. We welcome your contributions.

Need support?

Our support engineers are available to help with service issues, billing, or account related questions, and can help troubleshoot build configurations. Contact our support engineers by opening a ticket.

You can also visit our support site to find support articles, community forums, and training resources.