Skip to content
Back to skills

Clojure Aero

ASecurity

Aero is an EDN configuration library with reader tag extensions for profiles, environment variables, and references. Use when working with configuration files, environment-specific settings, or when you need explicit, intentful config management in Clojure.

  • 666 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added February 8, 2026
devopsgojavasqlawsgitapidatabase

Works with

  • api

Security analysis

A100/100

Scanned February 12, 2026

npx -y skills add majiayu000/claude-skill-registry --skill clojure-aero --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Clojure Aero?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Clojure Aero
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-clojure-aero/badge)](https://www.skillsdirectory.com/skills/majiayu000-clojure-aero)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: clojure-aero
description: Aero is an EDN configuration library with reader tag extensions for profiles, environment variables, and references. Use when working with configuration files, environment-specific settings, or when you need explicit, intentful config management in Clojure.
---

# Aero

A small library for explicit, intentful configuration using EDN with powerful reader tag extensions.

## Setup

deps.edn:
```clojure
aero/aero {:mvn/version "1.1.6"}
```

Leiningen:
```clojure
[aero "1.1.6"]
```

See https://clojars.org/aero for the latest version.

## Quick Start

```clojure
(require '[aero.core :refer [read-config]])

;; Create config.edn:
;; {:greeting "World!"
;;  :port #profile {:default 8000
;;                  :dev 8001
;;                  :prod 80}}

;; Read from classpath (recommended)
(read-config (clojure.java.io/resource "config.edn"))
;; => {:greeting "World!", :port 8000}

;; Read with profile
(read-config (clojure.java.io/resource "config.edn") {:profile :dev})
;; => {:greeting "World!", :port 8001}
```

## Core Concepts

Aero reads EDN configuration files with special reader tags that allow:
- Profile-based configuration (dev/test/prod)
- Environment variable injection
- References to other config values
- File inclusion for modular configs
- Type coercion (string to long/double/keyword/boolean)
- Conditional logic based on hostname, user, etc.

Always use `io/resource` to read from classpath - works in both REPL and JAR files. Direct file paths like `(read-config "config.edn")` fail in JARs.

## Reader Tags

### #profile - Environment-specific values

```clojure
{:webserver
  {:port #profile {:default 8000
                   :dev 8001
                   :test 8002
                   :prod 80}}}

;; Usage:
(read-config "config.edn" {:profile :dev})
;; => {:webserver {:port 8001}}
```

### #env - Environment variables

```clojure
{:database-uri #env DATABASE_URI}

;; Reads from (System/getenv "DATABASE_URI")
```

### #envf - Format with environment variables

```clojure
{:database #envf ["protocol://%s:%s" DATABASE_HOST DATABASE_NAME]}

;; Builds string from multiple env vars
```

### #or - Provide defaults

```clojure
{:port #or [#env PORT 8080]
 :debug #boolean #or [#env DEBUG "true"]}

;; First available value wins, uses 8080 if PORT not set
```

### #ref - Reference other config values

```clojure
{:db-connection "datomic:dynamo://dynamodb"
 :webserver {:db #ref [:db-connection]}
 :analytics {:db #ref [:db-connection]}}

;; Both :webserver and :analytics get same db-connection value
;; References use get-in vector paths
```

### #include - Modular configs

```clojure
{:webserver #include "webserver.edn"
 :analytics #include "analytics.edn"}
```

By default resolves relative to parent config. Use custom resolver:

```clojure
(require '[aero.core :refer [resource-resolver root-resolver]])

;; Always resolve from classpath
(read-config "config.edn" {:resolver resource-resolver})

;; Or provide a map
(read-config "config.edn"
  {:resolver {"webserver.edn" "resources/webserver/config.edn"}})
```

### #join - String concatenation

```clojure
{:url #join ["jdbc:postgresql://psq-prod/prod?user="
             #env PROD_USER
             "&password="
             #env PROD_PASSWD]}
```

### #merge - Merge maps

```clojure
{:config #merge [{:foo :bar} {:foo :baz :qux 123}]}
;; => {:config {:foo :baz :qux 123}}
```

### Type coercion tags

```clojure
{:port #long #or [#env PORT "8080"]           ; Parse string to Long
 :factor #double #env FACTOR                   ; Parse to Double
 :mode #keyword #env MODE                      ; Parse to keyword
 :debug #boolean #or [#env DEBUG "true"]}      ; Parse to boolean
```

### #hostname - Host-specific config

```clojure
{:webserver
  {:port #hostname {"stone" 8080
                    #{"emerald" "diamond"} 8081
                    :default 8082}}}
```

### #user - User-specific config

Like #hostname but switches on the current user.

## Common Patterns

### Hide passwords in local files

Don't put secrets in version control or env vars. Use private files:

```clojure
{:secrets #include #join [#env HOME "/.secrets.edn"]

 :aws-secret-access-key
  #profile {:test #ref [:secrets :aws-test-key]
            :prod #ref [:secrets :aws-prod-key]}}
```

### Wrap config access in functions

```clojure
(ns myproj.config
  (:require [aero.core :as aero]
            [clojure.java.io :as io]))

(defn config [profile]
  (aero/read-config (io/resource "config.edn") {:profile profile}))

(defn webserver-port [config]
  (get-in config [:webserver :port]))

;; Usage in app:
(let [cfg (config :prod)]
  (start-server :port (webserver-port cfg)))
```

This insulates your code from config structure changes.

### Feature toggles

```clojure
{:features
  {:new-ui #profile {:default false
                     :dev true
                     :staging true
                     :prod false}}}
```

### Component integration

Pass config to components without boilerplate:

```clojure
(defn configure [system profile]
  (let [config (aero/read-config (io/resource "config.edn")
                                 {:profile profile})]
    (merge-with merge system config)))

(defn new-system [profile]
  (-> (new-system-map)
      (configure profile)
      (system-using (new-dependency-map))))
```

## Custom Reader Tags

Extend the reader multimethod for custom tags:

```clojure
(require '[aero.core :refer [reader]])

(defmethod reader 'mytag
  [{:keys [profile] :as opts} tag value]
  (if (= value :favorite)
    :chocolate
    :vanilla))

;; In config.edn:
;; {:flavor #mytag :favorite}
```

## Gotchas

1. File paths vs resources: Use `(io/resource "config.edn")` not `"config.edn"` to avoid JAR deployment failures

2. Environment variables for secrets: Don't use #env for passwords - they leak via `ps` and monitoring. Use #include with private files instead

3. Single config file: Keep one config file when possible - easier to manage and less duplication

4. #or evaluation order: Tags evaluate left to right, first non-nil wins

5. References are recursive: #ref works across #include boundaries

6. Profile is just a key: Can be any keyword - :dev, :prod, :staging, :local, etc.

## Advanced: Macro Tag Literals (Alpha)

For custom conditional constructs, use the alpha API:

```clojure
(ns myns
  (:require [aero.alpha.core :as aero.alpha]))

(defmethod aero.alpha/eval-tagged-literal 'myprofile
  [tagged-literal opts env ks]
  (aero.alpha/expand-case (:profile opts) tagged-literal opts env ks))
```

See README for #or implementation example.

## References

- GitHub: https://github.com/juxt/aero
- Clojars: https://clojars.org/aero
- API Docs: https://cljdoc.org/d/aero/aero/
- Community: #juxt channel on Clojurians Slack
- Extensions: https://github.com/monkey-projects/aero-ext

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.