Building, Packaging and Deployment
45.1 tools.build: Uberjars
The main namespace needs (:gen-class) in its ns form and a -main function for AOT/uberjar entry points.
;; build.clj
(ns build
(:require [clojure.tools.build.api :as b]))
(def lib 'myorg/myapp)
(def version "1.0.0")
(def class-dir "target/classes")
(def basis (delay (b/create-basis {:project "deps.edn"})))
(def uber-file (format "target/%s-%s-standalone.jar" (name lib) version))
(defn clean [_] (b/delete {:path "target"}))
(defn uber [_]
(clean nil)
(b/copy-dir {:src-dirs ["src" "resources"] :target-dir class-dir})
(b/compile-clj {:basis @basis :ns-compile '[myapp.core] :class-dir class-dir})
(b/uber {:class-dir class-dir :uber-file uber-file :basis @basis :main 'myapp.core}))clj -T:build uber
java -jar target/myapp-1.0.0-standalone.jar45.2 Docker and Native Images
GraalVM native-image compiles to a native binary (fast startup, low memory). It needs reflection configuration; see clj-easy/graal-build-time. Startup can also be improved with AOT compilation, Class Data Sharing (CDS), and the JDK's AppCDS/Leyden features.
FROM clojure:temurin-21-tools-deps AS build
WORKDIR /app
COPY deps.edn build.clj ./
RUN clojure -P -T:build # pre-download dependencies
COPY src src
COPY resources resources
RUN clojure -T:build uber
FROM eclipse-temurin:21-jre
COPY --from=build /app/target/*-standalone.jar /app/app.jar
EXPOSE 3000
CMD ["java", "-XX:+UseZGC", "-jar", "/app/app.jar"]45.3 Libraries and CI
Publish libraries to Clojars (deps-deploy), or consume them directly as git dependencies.
CI: GitHub Actions with DeLaGuardo/setup-clojure, cache ~/.m2 and ~/.gitlibs, run clj-kondo, cljfmt check, tests, and the build.