Dagger SDK for Clojure #
A personal, unofficial experimental SDK targeting Dagger 1.0.0-beta.21. It is not maintained or endorsed by the Dagger team.
Write pipelines with ordinary Clojure functions, thread them with ->, pass
optional arguments as maps, and manage sessions with with-open. Engine objects
are lazy; scalar results execute the query. Failures throw ex-info with useful
ex-data, including GraphQL errors.
Get started #
From this checkout’s root:
mise trust
mise install
cd clojure
mise trust
mise install
mise exec -- clojure -M:test
The root configuration pins Dagger beta.21; this directory pins Temurin JDK 21
and the Clojure CLI. The SDK is not published to Clojars. Add a local dependency
to your application’s deps.edn:
{:deps {personal/dagger {:local/root "/absolute/path/to/dagger-sdk/clojure"}}}
(require '[dagger.core :as dag]
'[dagger.container :as container])
(with-open [client (dag/connect)]
(println (-> (dag/container client)
(container/from "alpine:3.22")
(container/with-exec ["echo" "Hello from Clojure!"])
container/stdout)))
dag/connect reuses an inherited Dagger session when present, or starts the
Dagger CLI from PATH. Closing the client only stops sessions it owns. Run with
mise exec -- clojure ... to select this repository’s CLI pin. A live engine
requires Docker or a configured Dagger engine.
Explore the runnable examples for a pipeline and a module.
Write a Dagger module #
Use normal defn forms. Mark exported functions with :dagger/return; parameter
hints such as ^String provide argument types. Unmarked helpers stay private to
the application. from-ns discovers exported public vars and constructs the
module definition.
(ns dagger-main
(:require [dagger.modules :as modules]))
(defn ^{:dagger/return :string} hello
"Greet someone."
[^{:tag String :dagger/default "world"} name]
(str "Hello, " name "!"))
(defn -main [& _]
(modules/serve! (modules/from-ns 'dagger-main "HelloClojure")))
Use :dagger/type metadata for richer parameter types, and ^:dagger/context
for the injected context containing :client and :parent. Exported functions
must have one fixed arity. Types include :string, :int, :float, :boolean,
:void, [:optional type], [:list type], and [:object "Container"].
For custom state, constructors, enums, and additional objects, use the explicit
module map API in dagger.modules.
Follow the module example instructions to
install this custom SDK, scaffold a module, and invoke it with beta.21. The Go
bootstrap installs the toolchain and generates bindings; your functions and
registration/invocation logic run in Clojure. Generated bindings are kept in
dagger-sdk/ inside the module project.
Develop and test #
Run from clojure/:
mise exec -- clojure -M:test
mise exec -- clojure -M:generate --check
mise exec -- clojure -M:integration
Unit tests cover transport errors, lazy selections, argument encoding, module registration/invocation, metadata exports, scaffolding, and generated bindings. The integration command requires an engine. GitHub Actions runs unit tests and live client checks; module checks can also be run from the repository root:
mise exec -- python3 scripts/test-module.py clojure
Regenerate bindings after updating schema/introspection.json:
mise exec -- clojure -M:generate
Edit the generator, not generated namespaces. Schema provenance describes the bundled snapshot. Module generation uses the engine’s schema, so installed module dependencies get their own bindings.
License #
Original code is MIT licensed. Upstream schemas and derived API documentation retain Apache-2.0 licensing; see NOTICE.