Browse Learn Clojure Foundations as a Java Developer

Atoms, Refs, Agents, and Vars

Choose the right Clojure reference type for changing identity: atoms for independent synchronous state, refs for coordinated transactions, agents for asynchronous updates, and Vars for namespace or dynamic context.

Clojure separates immutable values from managed references. A value can be shared freely because it does not change. A reference is the explicit place where a newer value can replace an older value.

For Java engineers, the important shift is that state is not hidden behind many setter methods. You choose a reference type based on coordination:

Tool Best fit Java comparison
Atom One independent identity that changes synchronously. AtomicReference with functional updates.
Ref Several identities that must change together. Database transaction more than synchronized.
Agent One independent identity updated asynchronously. Serialized worker queue with state.
Var Namespace definition or dynamic per-thread context. Static binding plus scoped thread context.

This section is a decision guide. Start with values and pure transition functions, then add the smallest reference type that matches the coordination problem.

In this section

  • Choose Clojure State Tools
    Compare atoms, refs, agents, and Vars from a Java engineer's perspective so each changing identity has the right coordination model instead of an accidental lock or global variable.
  • Use Atoms for Independent State
    Use Clojure atoms when one in-process identity must change synchronously, and keep `swap!` update functions pure because they may be retried under contention.
  • Coordinate State with Refs and STM
    Use refs and software transactional memory when several in-process identities must change together, and keep transactions pure because Clojure may retry them.
  • Use Agents for Asynchronous State
    Use agents when one independent Clojure state value should receive serialized asynchronous updates, and choose `send` or `send-off` based on CPU-bound versus blocking work.
  • Understand Vars and Dynamic Bindings
    Understand Clojure Vars as namespace bindings, REPL-redefinable roots, and carefully scoped dynamic context rather than ordinary mutable Java variables.
Revised on Saturday, May 23, 2026