Browse Learn Clojure Foundations as a Java Developer

Keywords in Clojure

Use Clojure keywords as self-evaluating labels for maps, statuses, options, qualified domain attributes, and data-first APIs.

Keywords are compact literal labels. They evaluate to themselves, compare efficiently, and work naturally as map keys.

1:status
2;; => :status

That self-evaluating behavior is the core difference from symbols. A symbol is usually resolved. A keyword is already the value.

Where Keywords Fit

Use case Example Java comparison
Map keys :user/email Field names or JSON property names
Status values :active, :cancelled Enum constants
Options {:mode :strict} Configuration constants
Event names :order/submitted Event type constants
Spec or validation names :user/id Qualified domain attribute names

In Java, these concerns often require string constants, enums, getters, annotations, or wrapper classes. In Clojure, keywords provide a language-level literal for stable data vocabulary.

Keywords as Map Keys

1(def user
2  {:user/id 42
3   :user/email "dev@example.com"
4   :user/status :active})

You can use a keyword as a function to look itself up in a map:

1(:user/email user)
2;; => "dev@example.com"
3
4(:user/role user :guest)
5;; => :guest

The optional third form above is a default value. get is also fine:

1(get user :user/email)
2;; => "dev@example.com"

Use the form that reads best in context. Keyword-as-function is common for simple lookups. get, get-in, and destructuring often read better when access is nested or dynamic.

Qualified Keywords

Bare keywords like :id and :name are fine in small examples. Larger systems benefit from qualified keywords:

1{:user/id 42
2 :invoice/id 9001
3 :account/id 7}

The namespace part does not load code. It gives the data label durable context.

Qualified keywords help when:

  • multiple domains share field names such as id, name, or status
  • validation rules use attribute names
  • data crosses subsystem boundaries
  • destructuring needs to remain clear

Auto-Resolved Keywords

Double-colon keywords use the current namespace or an alias:

1(ns my.app.user-service
2  (:require [my.app.user :as user]))
3
4::local-id
5;; => :my.app.user-service/local-id
6
7::user/id
8;; => :my.app.user/id

Use this when the namespace qualification should follow aliases instead of being repeated as a string-like prefix. This is common in specs, validation, and library APIs.

Keywords as Enum-Like Values

Keywords are often the simplest status representation:

1(defn transition [order]
2  (case (:order/status order)
3    :draft     (assoc order :order/status :submitted)
4    :submitted (assoc order :order/status :paid)
5    :paid      order
6    :cancelled order))

This is lighter than a Java enum, but it shifts discipline to the data model. A typo creates a different keyword. Centralize important state transitions and validate external inputs.

Boundary Rule: Strings Outside, Keywords Inside

External systems usually speak strings:

  • JSON object keys
  • HTTP parameters
  • database column names
  • message payloads

Inside Clojure application code, keywords are often the better shape:

1(defn normalize-status [s]
2  (case s
3    "active" :active
4    "disabled" :disabled
5    "pending" :pending
6    :unknown))

Do the conversion deliberately at boundaries. Avoid calling keyword on arbitrary untrusted strings without a bounded vocabulary. It can create unbounded keyword values that are retained for the life of the process in many Clojure/JVM environments.

Common Mistakes

Mistake Better habit
Using strings as internal map keys by default Use qualified keywords for stable domain attributes
Using :id everywhere in a large system Prefer :user/id, :order/id, :invoice/id
Treating keyword namespaces as code namespaces Remember they are data labels unless auto-resolved by ::
Creating keywords from unbounded input Validate against known values first
Using keywords as function names Use symbols for code names

Practice

  1. Rewrite {"userId" 42 "status" "active"} as an internal Clojure map.
  2. Add a boundary function that converts "active" and "disabled" strings to status keywords.
  3. Replace bare keys :id and :name in a larger data shape with qualified keys.
  4. Compare (:missing user :guest) and (get user :missing :guest).

Key Takeaways

  • Keywords evaluate to themselves.
  • Keywords are the normal choice for map keys, statuses, options, and data labels.
  • Qualified keywords keep larger data models clear.
  • :: auto-resolves keyword namespaces through the current namespace or aliases.
  • Convert external strings to internal keywords deliberately and safely.

Quiz: Keywords in Clojure

### What does a keyword evaluate to? - [x] Itself. - [ ] The var with the same name. - [ ] A Java enum automatically. - [ ] A mutable field. > **Explanation:** Keywords are self-evaluating literal values. ### What is a common internal use for keywords? - [x] Map keys and status values. - [ ] Function parameter names. - [ ] Java class imports. - [ ] Loop mutation. > **Explanation:** Keywords are excellent data labels for maps, statuses, options, and event types. ### What does `(:user/email user)` do? - [x] Looks up `:user/email` in the `user` map. - [ ] Resolves a var named `user/email`. - [ ] Imports a Java field. - [ ] Converts the map to a string. > **Explanation:** Keywords can be called as functions to look themselves up in associative data structures. ### Why are qualified keywords useful? - [x] They add domain context and reduce key collisions. - [ ] They automatically load code. - [ ] They make values mutable. - [ ] They replace all namespaces. > **Explanation:** Qualified keywords such as `:user/id` and `:invoice/id` make data vocabulary clearer. ### True or False: It is always safe to call `keyword` on arbitrary user input. - [ ] True - [x] False > **Explanation:** Convert external strings to keywords through a bounded vocabulary. Avoid creating unbounded keywords from untrusted input.
Revised on Saturday, May 23, 2026