Open-source project
technomancy/leiningen avatar
technomancy/leiningen

Leiningen: the Clojure build tool that now lives on Codeberg

Moved to Codeberg; this is a temporary convenience mirror

7,296 stars1,567 forksClojureNOASSERTION

At a glance

What is it?
Leiningen is the long-running build and dependency tool for Clojure, and its repository has moved off GitHub to Codeberg. This article covers what the tool does, how to install it, and where its design shows its age.
Who is it for?
Leiningen is the right choice if you maintain an existing project.clj build, or if you want one tool that handles dependencies, compilation, testing, packaging and task running for Clojure. It is the wrong choice if you are starting fresh and want to compose small official tools, since deps.edn and the Clojure CLI cover dependency resolution and classpath construction without a project DSL.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 113 days ago.
What is it written in?
Mainly Clojure, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 21, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Leiningen solves, and for whom

Clojure runs on the JVM, which means a project needs a dependency resolver, a classpath builder, a compilation step and a way to run tests and package artifacts. Leiningen bundles all of that behind one command, lein, and one project file, project.clj. The README does not restate this because by now it is assumed knowledge: Leiningen has been the default Clojure build tool for most of the language's life. The repository layout confirms the scope. Top-level entries include leiningen-core/ for the build engine itself, src/ for the CLI, test/ and test_projects/ for its own suite, plus bash_completion.bash, zsh_completion.zsh and pcmpl-lein.el for shell integration. That is not a thin wrapper around Maven. It is an application with its own task system.

The audience is Clojure developers with an existing project.clj, and teams that want one binary to own the whole build lifecycle. If you have ever written a Makefile to sequence javac, a test runner and a jar packer, Leiningen is the Clojure-shaped version of that idea. The cost is that you adopt its opinions about project structure, and its task vocabulary becomes the vocabulary your team uses.

project.clj as the build definition, and what lein does with it

The mechanism is a Clojure file evaluated at startup. Leiningen reads project.clj, evaluates the defproject form inside it, and derives a dependency graph, a classpath and a set of runnable tasks. Because the file is Clojure rather than a data-only format, the build definition can compute values, read environment variables and call functions. That is the central design decision, and it cuts both ways. You get real programming power in your build file. You also get a build file that can fail in ways only a Clojure stack trace explains.

The repository ships sample.project.clj at the top level, which is the canonical place to see the keys the tool accepts. The doc/ directory holds the prose documentation. Dependencies resolve through the JVM ecosystem, so artifacts come from Maven repositories, and Leiningen layers its own resolution and task dispatch on top. leiningen-core/ is where that engine lives, separate from the command-line front end in src/, which is why the project can be consumed as a library by other tools.

The task model is the part people underestimate. Tasks are not a fixed list compiled into the binary; they can be provided by plugins, and the same dispatch runs built-in tasks and plugin tasks. That is why a Leiningen project can grow a release pipeline, a lint step and a documentation build without adding a second build system. It is also why a broken plugin can break unrelated commands, since the plugin's code loads into the same process.

Installing Leiningen and running a first project

The README in this repository is a migration notice, not an install guide. It points readers to the Codeberg repository and to the #leiningen IRC channel on Libera.Chat for discussion. The install instructions themselves live in the project's documentation, which the repository keeps under doc/. What the README does state, in a note addressed to packagers, is that the Leiningen uberjars continue to be hosted on GitHub so downstream scripts that download them keep working, while the source repository is on Codeberg.

Because the README here gives no install steps, there is no command to reproduce from it. The place to get Leiningen is the Codeberg repository it points to, and the launcher is the lein script that the project's own documentation describes under doc/. What the README does confirm is the artifact story: uberjars stay on GitHub for packagers, and everything else moves.

Once lein is on your PATH, the two commands a new user reaches for are project creation and the test run. The repository does not spell either out in the README, so treat the task names as the vocabulary to look up in doc/ rather than as a snippet to copy from here. The shell integration files at the top level, bash_completion.bash and zsh_completion.zsh, exist so that task and option names complete in your shell, which is the practical way to discover what lein accepts without leaving the terminal.

The repository moved, and the mirror is not the project

The most important operational fact about this repository is that it is a convenience mirror. The README's first line is a greeting to GitHub users, followed by a request to switch git remotes to https://codeberg.org/leiningen/leiningen. The project states it moved off GitHub deliberately, citing the Software Freedom Conservancy's GiveUpGitHub campaign, and it frames Codeberg as a user-owned cooperative with a democratic governance model.

For anyone consuming the source, that changes the workflow. Issues, pull requests and the canonical history are on Codeberg. The GitHub mirror exists so that packaging scripts that download uberjars keep working, and the README says the uberjars are the only thing that will continue to be updated here. Read that sentence carefully: if you clone this repository expecting current source, you are reading a mirror whose stated purpose is hosting release artifacts. The last push recorded for this repository is 2026-06-08, the same date as the 2.13.0 release, which is consistent with a mirror that is updated when artifacts are published rather than on every commit.

There is also a licensing statement in the README that is unusual for an open source project. It says any use of the project's code by GitHub Copilot, past or present, is done without permission, and that the project does not consent to its data being used to train Copilot or any other language model. The repository's licence file is COPYING, and the repository metadata reports the licence as NOASSERTION rather than a recognised SPDX identifier. If your organisation requires a machine-readable licence classification, that is something to resolve before you vendor the code.

Where Leiningen is the wrong tool

Leiningen's build file is executable Clojure. That is a genuine feature, but it means a project.clj can encode arbitrary logic that no other tool can inspect. When a build breaks, the failure may be in user code inside the build file rather than in Leiningen itself, and the debugging surface is the whole Clojure runtime. Teams that want a declarative, data-only build definition will find this heavier than they want.

The second limitation is the one the ecosystem has been moving away from. deps.edn plus the Clojure CLI resolves dependencies and builds a classpath from a data file, and it composes with small tools rather than owning the lifecycle. Leiningen owns the lifecycle. If your workflow is already a set of shell commands and CI steps that each do one thing, adopting Leiningen means either duplicating that logic as tasks or leaving it outside the tool, at which point you have two build systems and one of them is undocumented.

Third, this repository is not where development happens. If you file an issue or open a pull request against the GitHub mirror, you are working against a copy that the maintainers describe as temporary. The README gives no rollback or migration procedure for projects mid-upgrade, and it does not document how the mirror is synchronised. That silence matters if your CI clones this URL on every build.

deps.edn and the Clojure CLI as the alternative

The real alternative is the official tooling: a deps.edn file consumed by the Clojure CLI. The difference in approach is not cosmetic. deps.edn is data, not code. It declares dependencies and aliases, and the CLI builds a classpath from that declaration. There is no task system, no plugin mechanism and no project DSL. You get dependency resolution and classpath construction, and everything else is a separate tool you choose.

That trade is the inverse of Leiningen's. With Leiningen you get a single entry point and a large surface to learn. With deps.edn you get a small, inspectable core and you assemble the rest. For a library that only needs a classpath and a test runner, the smaller tool is easier to reason about in CI. For an application that needs compilation, packaging, a release task and a plugin-provided lint step, Leiningen's task dispatch saves you from wiring those pieces together yourself.

Neither choice is about capability. Both resolve from Maven repositories. The question is whether you want the build lifecycle owned by one tool with an executable configuration file, or distributed across small tools with a declarative one. Projects already on project.clj have a migration cost in either direction, and nothing in this repository documents that migration.

Editorial conclusion

Leiningen is the right choice if you maintain an existing project.clj build, or if you want one tool that handles dependencies, compilation, testing, packaging and task running for Clojure. It is the wrong choice if you are starting fresh and want to compose small official tools, since deps.edn and the Clojure CLI cover dependency resolution and classpath construction without a project DSL. Before adopting it, verify that the Codeberg repository is the one you are tracking, that your build scripts do not clone from the GitHub mirror expecting fresh source, and that the uberjar URL your packaging scripts use still resolves.

Frequently asked questions

How do you install Leiningen?

The README in this repository does not contain install steps; it points to the Codeberg repository and to the #leiningen IRC channel on Libera.Chat for discussion. The install documentation is kept under doc/ in the project's own documentation.

How do you install Leiningen on Windows?

This repository does not document a Windows installation. The README is a migration notice that points to Codeberg and to the #leiningen IRC channel, and the install instructions live under doc/ in the project's own documentation.

How does Leiningen compare with deps.edn?

Leiningen reads an executable project.clj and owns the build lifecycle through its task system, including plugins. deps.edn is a data file consumed by the Clojure CLI that resolves dependencies and builds a classpath, leaving other steps to separate tools.

How does Leiningen compare with the Clojure CLI?

The Clojure CLI builds a classpath from a deps.edn declaration and does not provide a task system or plugin mechanism. Leiningen bundles dependency resolution, compilation, testing, packaging and task running behind the lein command.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. technomancy/leiningen on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/technomancy-leiningen.svg)](https://hysenlabs.com/projects/technomancy-leiningen)