Note: This page covers the architecture of the (JVM-based) Clojure implementation. So, it may not accurately describe some aspects of other variants (eg, ClojureCLR, ClojureScript). Basically, YMMV (:-).


Clojure is basically a Lisp implementation, based on a reader, an evaluator/compiler, and a virtual machine. The evaluator/compiler accepts incoming code (encoded as Clojure data structures), handles expansion of syntactic macros, and compiles the result into Java bytecode.

The bytecode is loaded and run by the Java Virtual Machine (JVM). The choice of the JVM is unusual for a Lisp, but it allows Clojure to take advantage of the entire Java ecosystem: community, libraries, tooling, etc. This capability is further supported by Clojure's interoperability support, use of Java data types, etc.

Data Flow

The diagram below is adapted from the "Syntactic Abstraction" slide in Rich Hickey's video, Clojure for Java Programmers. It shows Clojure's overall architecture and typical data flows:

    Clojure's Architecture and Data Flow


  • The Reader accepts Clojure source code (characters) from the REPL (Read/Eval/Print Loop) and/or code file(s).

  • The Reader's output (Clojure data structures, encoding an Abstract Syntax Tree) is sent to the evaluator/compiler for further processing. Other data structures (ie, ASTs) may come in from running program(s).

  • If the evaluator/compiler detects invocation of a macro, it sends the current data structures off for macro expansion. The expanded versions are accepted in place of the originals. This process is repeated until all macros have been resolved.

  • The resulting data structures, consisting of function calls and values, are compiled into collections of Java bytecode.

  • The generated bytecode is sent to the JVM (Java Virtual Machine) for execution. Assorted optimizations are typically performed by the JVM at runtime.

  • The running bytecode performs input and/or output, as appropriate.

This architecture allows some interesting possibilities. For example, program code can be created and/or modified at runtime, either via the REPL or by another part of the program.

This wiki page is maintained by Rich Morin, an independent consultant specializing in software design, development, and documentation. Please feel free to email comments, inquiries, suggestions, etc!

Topic revision: r7 - 05 Mar 2013, RichMorin
This site is powered by Foswiki Copyright © by the contributing authors. All material on this wiki is the property of the contributing authors.
Foswiki version v2.1.6, Release Foswiki-2.1.6, Plugin API version 2.4
Ideas, requests, problems regarding CFCL Wiki? Send us email