Jolt is a self-hosted Clojure implementation that runs on
a portable Scheme layer that supports multiple backends.
Chez natively, Gambit for JavaScript, no JVM. Most Clojure
runs unchanged, any C library binds natively, and jolt build
ships a single standalone binary.
defcfn turns C functions into ordinary Clojure fnsjolt build emits a single standalone binary with C dependencies linked in staticallyfuture, agent, pmap, and core.async on OS threadsThe terminal on the right is jolt itself — compiled to JavaScript by the Gambit backend — evaluating live in your browser. It runs a reduced build to keep the download small, so regex is left out here and says so if you reach for it.
Bind any C shared library: declare it, wrap functions with defcfn, call them with Clojure values. The db library reaches SQLite and Postgres this way; http-client binds OpenSSL and zlib.
jolt build ahead-of-time compiles a project — runtime, standard library, app, and its deps — into a single self-contained executable, with C dependencies linked statically. No Chez, no JVM, no source needed to run it.
Reads Clojure, analyzes it to a host-neutral IR, emits Scheme, and runs it — on Chez natively, or on Gambit compiled to JavaScript. The compiler is written in Clojure and compiles itself; Chez runs interpreted and compiled code identically, so the REPL and a built binary behave the same.
future/promise/agent/pmap run on OS threads over a shared heap, matching JVM semantics. core.async provides channels and go blocks.
Immutable vectors (32-way tries), cons lists, and HAMT maps/sets with Clojure value semantics. Transients are real mutable scratch collections.
Lazy/infinite seqs, transducers, destructuring, multimethods, protocols/records, metadata, namespaces, runtime eval, and the full reader.
Install the self-contained jolt binary — it bundles the runtime, compiler, and standard library, so there's nothing else to install.
# Homebrew
brew install jolt-lang/jolt/jolt
# or the install script (Linux / macOS)
curl -sL https://raw.githubusercontent.com/jolt-lang/jolt/main/install | bash
jolt -e '(+ 1 2)' # => 3
Or run from a clone (needs Chez Scheme) — no build step, the bootstrap seed is checked in:
git clone --recurse-submodules https://github.com/jolt-lang/jolt.git
cd jolt
jolt -e '(+ 1 2)' # => 3
$ jolt -e '(->> (range 10) (filter even?) (map (fn [x] (* x x))) (reduce +))'
# 120
$ jolt -e '(/ 1 2)'
# 1/2
jolt run -m myapp.core # resolve deps.edn, then run -main
jolt -M:test [args] # run an alias's :main-opts
jolt path # print the resolved source roots
jolt build -m myapp.core -o myapp # single self-contained executable
./myapp arg1 arg2 # runs anywhere; args reach -main
# --opt for the optimized build, --dev for an unoptimized one
(require '[jolt.ffi :as ffi])
(ffi/load-library "libsqlite3.dylib") ; or declare :jolt/native in deps.edn
(ffi/defcfn sqlite3-libversion "sqlite3_libversion" [] :string)
(sqlite3-libversion) ; => "3.51.0"
Any C library binds the same way — the native interop guide covers types, memory, structs, and static linking.
jolt --nrepl-server # auto-resolves deps.edn, writes .nrepl-port
# connect CIDER / Calva / Cursive via the .nrepl-port file, then
# redefine a var and the next call sees it — no restart
Develop against a live process: see REPL-Driven Development.
Read the documentation for installation, writing libraries, and C interop.
Jolt targets Clojure semantics but runs on Scheme, not the JVM. Most portable Clojure runs unchanged — persistent collections, the numeric tower, lazy seqs, transducers, multimethods, protocols/records, atoms, future/agent/pmap, core.async, runtime eval, and the full reader all behave as on the JVM. The genuine divergences:
| Aspect | Difference |
|---|---|
| Java interop | No JVM, so no general Java interop, reflection, or gen-class/proxy — a native C FFI takes its place, plus a shimmed subset of java.* |
| BigDecimal | Not available (decimal? is always false); the rest of the numeric tower matches |
| Regex | Compiled by irregex, not java.util.regex — common patterns work, some Java-specific features differ |