Browse Learn Clojure Foundations as a Java Developer

Create a deps.edn Project

Create a small Clojure CLI project by hand, wire source and test paths, add run and test aliases, and verify the project from the shell before adding more tooling.

A deps.edn project can start as a plain directory. That is part of the appeal: you do not need a generator to understand what exists on the classpath.

Create the Directory Layout

1mkdir orders-cli
2cd orders-cli
3mkdir -p src/orders test/orders resources

Target structure:

 1orders-cli/
 2├── deps.edn
 3├── resources/
 4├── src/
 5│   └── orders/
 6│       └── core.clj
 7└── test/
 8    └── orders/
 9        ├── core_test.clj
10        └── test_runner.clj

This is intentionally close to a small Java project: production code, test code, resources, and one project configuration file.

Write deps.edn

Create:

1{:paths ["src" "resources"]
2 :deps {org.clojure/clojure {:mvn/version "1.12.5"}}
3 :aliases
4 {:run {:main-opts ["-m" "orders.core"]}
5  :test {:extra-paths ["test"]
6         :main-opts ["-m" "orders.test-runner"]}}}

Each line has a job:

Entry Job
:paths ["src" "resources"] Production classpath roots
org.clojure/clojure Clojure runtime/library dependency
:run Main-entry command alias
:test Adds tests to the classpath and runs a test runner

Add Source Code

Create src/orders/core.clj:

1(ns orders.core)
2
3(defn order-total [order]
4  (reduce + 0 (:line-items order)))
5
6(defn -main
7  [& _]
8  (println
9   (order-total {:line-items [10 15 25]})))

This keeps the calculation testable and leaves printing in -main.

Run:

1clojure -M:run

Expected output:

150

Add a Test

Create test/orders/core_test.clj:

1(ns orders.core-test
2  (:require [clojure.test :refer [deftest is testing]]
3            [orders.core :as core]))
4
5(deftest order-total-test
6  (testing "adds line item amounts"
7    (is (= 50 (core/order-total {:line-items [10 15 25]})))))

Create test/orders/test_runner.clj:

1(ns orders.test-runner
2  (:require [clojure.test :as test]
3            [orders.core-test]))
4
5(defn -main
6  [& _]
7  (let [{:keys [fail error]} (test/run-tests 'orders.core-test)]
8    (when (pos? (+ fail error))
9      (System/exit 1))))

Run:

1clojure -M:test

The explicit runner makes this tiny project CI-friendly because a failed test produces a nonzero exit code.

Verify the Classpath

Before adding more dependencies, inspect the classpath:

1clojure -Spath

You should see src and resources. To inspect the test classpath:

1clojure -A:test -Spath

This habit helps Java engineers quickly diagnose namespace loading problems. Most early errors are path, namespace, or alias mismatches.

Add a Dependency

Add JSON support:

1{:paths ["src" "resources"]
2 :deps {org.clojure/clojure {:mvn/version "1.12.5"}
3        org.clojure/data.json {:mvn/version "2.5.2"}}
4 :aliases
5 {:run {:main-opts ["-m" "orders.core"]}
6  :test {:extra-paths ["test"]
7         :main-opts ["-m" "orders.test-runner"]}}}

Then require it from a namespace:

1(ns orders.core
2  (:require [clojure.data.json :as json]))

Adding a dependency changes the classpath. It does not automatically impose a build lifecycle.

When to Add More Tooling

Keep the first project small until these commands are boring:

Need Add later
Richer test runner Kaocha or another team-standard runner
Packaging tools.build or a team build script
Formatting/linting cljfmt, clj-kondo, or repo-standard tooling
Editor REPL Calva, Cursive, CIDER, or nREPL middleware
Deployment Container, jar, or platform-specific release process

Do not start by copying a large production deps.edn. Build your mental model first.

Key Takeaways

  • A deps.edn project can be created by hand with a small directory tree.
  • :paths controls the production classpath; aliases add task-specific paths and options.
  • Use clojure -M:run for the application and clojure -M:test for the small test runner.
  • Inspect the classpath with clojure -Spath before blaming Clojure code.
  • Add tooling after the run/test loop is clear.

Quiz: deps.edn Project

### What is the minimum useful role of `deps.edn` in this first project? - [x] Declare paths, dependencies, and run/test aliases - [ ] Store compiled `.class` files - [ ] Replace Git - [ ] Configure the operating system > **Explanation:** `deps.edn` describes classpath roots, dependencies, and command aliases. ### Why does the `:test` alias use `:extra-paths ["test"]`? - [x] Test namespaces should be available for test runs without leaking into normal runtime paths. - [ ] Clojure cannot load files from `src`. - [ ] Leiningen requires it. - [ ] Java forbids test directories. > **Explanation:** Aliases let you add test paths only when the test command needs them. ### Which command helps diagnose namespace loading and classpath problems? - [x] `clojure -Spath` - [ ] `git log` - [ ] `java -XshowSettings` - [ ] `lein new` > **Explanation:** `clojure -Spath` shows the classpath produced by your `deps.edn` and aliases.
Revised on Saturday, May 23, 2026