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); the bootstrap seed is checked in, so there is no build step:
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 |