Learn what Leiningen still does well, how project.clj works, and when Java developers should lean on it.
Leiningen is one of the oldest and most influential tools in the Clojure ecosystem. Even if you start new learning projects with the Clojure CLI and deps.edn, you will still encounter Leiningen in mature codebases, company projects, tutorials, and automation scripts.
For a Java developer, Leiningen feels familiar for good reasons:
That familiarity makes it a useful bridge into Clojure, even though it is not the only workflow you need to know.
Leiningen is a project automation tool organized around project.clj. It can:
If you come from Maven or Gradle, the mental model is not exact, but it is close enough to feel productive quickly.
project.clj Is The Center Of GravityA Leiningen project is usually centered on a project.clj file:
1(defproject my-app "0.1.0-SNAPSHOT"
2 :description "A sample Clojure app"
3 :dependencies [[org.clojure/clojure "1.12.4"]]
4 :main ^:skip-aot my-app.core
5 :profiles {:uberjar {:aot :all}})
You do not need to memorize every key at once. The practical ones to understand early are:
defproject for the project identity:dependencies for libraries:main for the entry namespace:profiles for environment-specific behaviorThat is already enough to read most small-to-medium Leiningen projects.
The best comparison is not “Leiningen is Maven written in Lisp.” The better comparison is:
You typically do not spend much time building custom build logic up front. Instead, you rely on a small set of well-known tasks:
1lein new app my-app
2lein test
3lein repl
4lein run
5lein uberjar
That is enough for many real applications.
It is easy for newcomers to hear “the official docs use the Clojure CLI” and conclude that Leiningen no longer matters. That is a mistake.
Leiningen still matters because:
lein repl, lein test, and lein uberjarSo the correct posture is not “pick a side.” It is “be able to read and work in either workflow.”
These are the commands a Java engineer should understand first:
lein newCreate a new project from a template:
1lein new app my-app
lein replStart a REPL with the project’s classpath and dependencies loaded:
1lein repl
This is often the fastest way to get an interactive session in an existing Leiningen codebase.
lein testRun the test suite:
1lein test
lein runRun the application’s main entry point:
1lein run
lein uberjarBuild a standalone jar with dependencies:
1lein uberjar
For Java developers used to packaging and deployment artifacts, this is one of the most immediately recognizable commands.
Leiningen becomes more powerful when you understand two extension points:
You do not need to use them early, but you should know they exist because many production codebases rely on them.
This is one reason Leiningen has remained sticky in long-lived applications: it can grow with the project without forcing you into a deeply custom build script on day one.
Use Leiningen confidently when:
project.cljlein commandsDo not fight the codebase. Follow its toolchain first.
The mental shift is:
That is why lein repl matters so much. It is not just “open a console.” It is “enter the project’s running development environment.”
project.clj mechanically without understanding which commands the team actually usesLeiningen is most valuable when used as part of the inner loop, not only at release time.