kimen

Clojure configuration and REPL secrets with Kimen

Keep using Aero, Environ, cprop or direct environment access. Move the secret values out of the project and supply them when the JVM starts.

Kimen guide, updated September 2026

Clojure projects assemble configuration in several ways.

Some applications read the JVM environment directly:

(def database-url
  (System/getenv "DATABASE_URL"))

Others turn one or more sources into Clojure data:

  • Aero reads explicit EDN configuration and supports #env, #profile, #include and other tagged values.
  • Libraries such as Environ, cprop and Omniconf merge or normalize environment variables, Java properties, files, command-line arguments and remote sources in different ways.

There are more variations, including custom EDN readers and Integrant or Component systems which receive an already assembled map. Kimen does not need to choose the application's configuration library.

In many deployed systems, the final source is still the process environment or a Java system property even when the rest of the application sees only a Clojure map. Other systems read a private file or fetch values from a remote secret manager.

The value still has to come from somewhere.

A configuration library can parse, merge and validate values. It does not remove the need for a source of authority:

  • An environment variable must be exported by a shell, process manager, container runtime or launch tool.
  • A private EDN file must exist on the developer's machine or runtime host.
  • A Java system property must be supplied when the JVM starts.
  • An application which calls Vault, AWS SSM or another secret manager still needs an identity or credential which authorizes that call.

Aero is unusually direct about this boundary. It supports #env, but recommends using environment variables sparingly and suggests a private included file for passwords because process environments can leak.

The Kimen question is not which Clojure library should win. It is where the local secret should live before Aero, Environ, cprop or the application reads it.

Kimen can supply the source your application already expects.

For environment-based configuration, keep the existing Clojure code and declare the runtime names in a Kimen profile:

# .kimen/profiles/dev.kmap
env DATABASE_URL=clojure_dev.database_url
env PAYMENTS_API_KEY=clojure_dev.payments_api_key
kimen run --profile dev -- clojure -M:dev

Aero can continue reading the environment:

{:database-url #env DATABASE_URL
 :payments-key #env PAYMENTS_API_KEY}

If the application already expects a private EDN file, Kimen can materialize one for the lifetime of the child process and expose only its path:

Store a single EDN map as the vault value. The value under clojure_dev.secrets_edn can contain fields such as :database-url and :payments-key.

Enter the map on one line through Kimen's hidden prompt rather than placing it in the project:

kimen secret set clojure_dev.secrets_edn

Then define the runtime file and the environment variable which points to it:

# .kimen/profiles/dev.kmap
file secrets.edn=clojure_dev.secrets_edn
envpath APP_SECRETS_FILE=secrets.edn

A committed Aero configuration can include that runtime path:

{:secrets #include #env APP_SECRETS_FILE}

Validate the profile and start the REPL:

kimen doctor --profile dev
kimen run --profile dev -- clojure -M:dev

Without a session, each command which opens the vault asks for its passphrase. For repeated REPL starts and development commands, use kimen session start --ttl 30m, then end the work period with kimen session lock.

Inside the REPL, verify only the key names:

(require '[aero.core :as aero])
(keys (:secrets (aero/read-config "config.edn")))
;; (:database-url :payments-key)

This file projection and nested #include #env form have been tested with Aero 1.1.6. Kimen removes the temporary file when the child process exits.

The Clojure process can read the resulting values. Kimen removes the need for a permanent plaintext copy inside the project. It does not hide secrets from the application which legitimately consumes them.

A long-running REPL keeps its environment.

Kimen supplies the selected values to the JVM when it starts. The REPL and code evaluated inside it can read those values for the lifetime of that process.

That is correct for a trusted application REPL. It is not isolation from code evaluated in the REPL, editor middleware attached to it or libraries loaded into the JVM.

Give the REPL its runtime without keeping the values beside the code.

Commit the profile, keep the values local and start the normal Clojure process through Kimen.

Install Kimen