Compare Leiningen and deps.edn by repository signals, team workflow, REPL expectations, testing, packaging, and migration cost so Java engineers choose tools pragmatically.
Choosing between Leiningen and deps.edn is less about declaring a winner and more about respecting the project you are in. A Java engineer should first ask: “Which tool owns this repository’s classpath, REPL, tests, and packaging?”
| Repository signal | Default action |
|---|---|
project.clj exists and README uses lein |
Use Leiningen |
deps.edn exists and README uses clojure or clj |
Use the Clojure CLI |
| Both files exist | Read the README and CI before assuming ownership |
build.clj exists with a :build alias |
Expect tools.build or CLI tool tasks |
| CI uses one command family consistently | Match CI first |
Do not start by asking which tool is newer. Start by identifying the tool that the project actually runs.
| Concern | Leiningen | deps.edn and Clojure CLI |
|---|---|---|
| Main file | project.clj |
deps.edn |
| Typical REPL | lein repl |
clj, editor REPL, or nREPL alias |
| Run app | lein run |
clojure -M:run |
| Run tests | lein test |
Alias, test runner, or clojure -M:test |
| Package app | lein uberjar |
Often tools.build or a team script |
| Extension model | Plugins and profiles | Aliases, tools, and ordinary namespaces |
| Best fit | Mature apps with established tasks | Lightweight classpath composition and explicit tooling |
The Clojure CLI is intentionally smaller. Leiningen is intentionally more project-task oriented. Both can be professional tools.
flowchart TD
A["Existing repository?"] -->|Yes| B["Follow README and CI"]
A -->|No| C["Need built-in app tasks and uberjar now?"]
B --> D["Use the tool already owning classpath/tests/package"]
C -->|Yes| E["Leiningen is a simple first choice"]
C -->|No| F["deps.edn keeps the project lightweight"]
F --> G["Add tools.build only when packaging is needed"]
E --> H["Keep project.clj small and use lein repl"]
The diagram is deliberately conservative: tool choice should reduce friction, not create identity work.
Choose Leiningen when:
project.clj codebaselein test, lein repl, or lein uberjarLeiningen is especially approachable for Java engineers who expect named build tasks and one project file.
Choose deps.edn when:
tools.build only when packaging becomes necessarydeps.edn is not “less serious” because it is small. It is a different model: compose classpaths and invoke functions deliberately.
Migrating from one tool to another is not only a file conversion.
| Hidden cost | Why it matters |
|---|---|
| README commands | Every onboarding instruction changes |
| CI scripts | Build/test/deploy commands may need rewrites |
| Editor setup | REPL connection commands may change |
| Packaging | Uberjar or build script behavior must be revalidated |
| Profiles and aliases | Environment-specific behavior may not translate directly |
| Plugins | Leiningen plugins may need separate CLI tools |
Migrate only when the benefit is concrete: simpler CI, fewer plugins, clearer classpath, better tool-task separation, or alignment with the team’s current standards.
Use this default:
| Situation | Recommendation |
|---|---|
| Joining an existing project | Use the existing toolchain |
| Learning project automation | Learn Leiningen enough to read project.clj |
| Learning modern classpath composition | Learn deps.edn aliases and CLI modes |
| Starting a tiny app | Either is fine; pick one and document commands |
| Starting a library | deps.edn is often a natural fit |
| Need an uberjar immediately | Leiningen is the shortest path; CLI projects commonly add tools.build |
The wrong choice is usually not “Leiningen” or “deps.edn.” The wrong choice is mixing both without clear ownership.
deps.edn provides explicit classpath composition and composable CLI modes.