Library / SDK
clj-easy/graalvm-clojure avatar
clj-easy/graalvm-clojure

graalvm-clojure: a compatibility matrix for Clojure libraries under native image

This project contains a set of "hello world" projects to verify which Clojure libraries do actually compile and produce native images under GraalVM.

523 stars51 forksClojureApache-2.0

At a glance

What is it?
graalvm-clojure is a set of small Clojure projects, one per library, whose only purpose is to check whether that library compiles and produces a native image under GraalVM. The table of results in the README is a practical compatibility list, with tick marks for the libraries that work, a warning for one that needs care and crosses for the ones that fail.
Who is it for?
Adopt the graalvm-clojure project as a checklist before you attempt a Clojure native image, since its per-library projects tell you in advance which dependencies will compile and which will not. Skip it as a library or a build template, because it is a compatibility corpus rather than a tool.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 26 days ago.
What is it written in?
Mainly Clojure, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the project is for

The README states the purpose in the first two sentences. The project contains a set of hello world projects to verify which Clojure libraries do actually compile and produce native images under GraalVM. The emphasis is on the word actually, and that word carries the whole point of the repository. Compiling a Clojure program to a native image is not the same as compiling a Java program to a native image, because Clojure compiles to Java bytecode at runtime and leans on the Java runtime for reflection, dynamic class loading and a large amount of runtime metadata. A library that works perfectly on the JVM can therefore fail at native image time, and the failure usually surfaces as a missing reflection configuration or a class that cannot be found at build time rather than as anything the library's own documentation would warn you about. So the project does the experiment for you, one library at a time, and records the answer. The repository is Apache-2.0 licensed, the primary language is Clojure, the default branch is master, and the last push to the repository was on 2026-09-27. There are no GitHub releases, which fits a project whose output is a directory of test cases rather than a distributable artefact.

How the results are presented

The list of tested libraries is given as a table with four columns, a status, the library with a link to its own directory in the repository, a description of what the library is and a remarks column. The status column is a small set of symbols rather than words, and the table mixes them, so the information is in the pattern rather than in the vocabulary. Most entries carry a check mark, which is the ordinary case of a library that compiles and produces a native image. Two entries carry a cross, which marks a library that does not work, and one carries a warning, which marks a library that works with a caveat. The remarks column carries the caveats in prose, and reading them is the useful part of the table. One failed entry is clj-sophia, described as a fast RAM-Disk hybrid storage, with the remark that it produces a runtime error involving JNA. Another failed entry is monger, an idiomatic Clojure MongoDB driver with sane defaults. The entry marked with a warning is fastmath, a fast and primitive math and stats library, with the remark pointing at its own README. Several successful entries also carry remarks, and those describe the conditions under which they succeed rather than a plain pass. clj-uuid works but has no objects in namespaced uuids, and clara-rules works but only when using an AOT compiled session. That last remark is the clearest example of the pattern the whole project is documenting, since a library can compile and still require a specific setup to work.

The libraries that compile

The bulk of the table is a check mark, and the descriptions show the range of the Clojure ecosystem covered. The foundations come first, with Clojure core and Clojure Spec, followed by the logging libraries clojure/tools.logging and clojure/tools.logging with log4j. The web stack is represented by aleph, described as a web server, http-kit as a web server and server, ring with Jetty, and pedestal. The list also covers the data side, with asami as an Asami DB, datascript as an immutable database and Datalog query engine, next.jdbc with honeysql as a database driver and SQL in Clojure, monger as an idiomatic Clojure MongoDB driver with sane defaults, and pg2-core. On the AWS side there are amazonica with s3 as a cloud API wrapper library and aws-api with s3 as the Cognitect AWS client library. The utility and general purpose libraries include cheshire as a JSON parser and writer, clj-http-lite as a web client, clj-uuid for RFC4122 unique identifiers, cljfmt as a source formatter, clostache as mustache for Clojure, hiccup as a fast library for rendering HTML in Clojure, hickory, loom as a Graph manipulation and computation library, component for managing lifecycle and dependencies of software, integrant as an alternative to mount and component, cprop for configuration and property management, lacinia as a GraphQL server implementation in pure Clojure, nippy as a Clojure serialization and deserialization library, mulog as an event logging system, timbre, selmer, safely, secure-random, roaring, zetasketch, upit, buffy which is described as Buffy the Byte Buffer Slayer, cli4clj for interactive command line interfaces for Clojure applications, pp-grid as a text formatting library, fire as a lightweight Clojure client for Firebase using the REST API, and the ml.dataset library from the tech.ml.dataset directory. The distribution libraries at the top of the repository show the same list as folders, one per library, which is what makes the table actionable rather than merely informative.

Why the native image question is different for Clojure

The reason this kind of project is needed at all is that a native image build and a Clojure program have a mismatch in their assumptions. A native image is built ahead of time and cannot include anything it cannot see, while Clojure resolves classes, namespaces and vars at runtime in ways that a static analyser has to be told about in advance. Every library that reaches into the runtime, into the classpath in a non-obvious way, or into a native library such as JNA, adds a case the build has to handle. That is why the failure remarks in the table mention JNA specifically for clj-sophia, since JNA is a native access bridge and a native image has to be told about it differently than the JVM would discover it. The successful entries with caveats show the same thing from the other side. clara-rules needs an ahead-of-time compiled session, which is a build configuration requirement rather than a code change, and clj-uuid loses the objects in namespaced uuids, which is a behaviour difference rather than a build failure. A compatibility table is more useful here than a yes or no, because the interesting question for an adopter is not whether a library works but under what conditions it works.

Building your own project the same way

The README says it also carries the instructions on how to build your own Clojure projects with GraalVM, and links three things. The first is a GraalVM download, pointing at the graalvm-ce-builds releases. The second is a document for building a hello world project, at the doc path clojure-graalvm-native-binary.md, and the third is an anchor within that same document for multi-platform builds with GitHub Actions.

bash
  - [Download a GraalVM](https://github.com/graalvm/graalvm-ce-builds/releases)
  - [Build a "Hello world!" project](./doc/clojure-graalvm-native-binary.md)
  - [Multi-platform builds with GitHub Actions](./doc/clojure-graalvm-native-binary.md#multi-platform-builds-with-github-actions)

That structure matters for how the repository is meant to be used. The per-library directories are the evidence, and the document is the recipe, so the project serves two audiences at once, the person who wants to know whether a dependency will compile, and the person who wants to compile their own application. The multi-platform anchor is the practical part for a team, since a native image is typically built for the platforms you ship to and a GitHub Actions workflow that produces several is how that is done without a local toolchain per platform. The doc directory at the top of the tree is where that document lives, and a sample-project directory sits alongside the per-library folders, which suggests the reference project is kept separately from the compatibility cases.

Where this project is the wrong guide

The first limit is that the table is a snapshot rather than a contract. Nothing in the README says which GraalVM version or which Clojure version each result was measured against, and native image support for a given library can change with either, so a tick mark from some past combination is evidence rather than a guarantee for your combination. The second is the coverage, which is broad across the popular libraries but plainly not exhaustive, since the repository holds about fifty directories and the Clojure ecosystem has far more, and a library that is absent is not thereby excluded. The third is that the granularity is per library rather than per application, and a real native image build succeeds or fails on the combination. A library that compiles in isolation can still fail when it sits next to another library that also injects runtime configuration, and the table cannot tell you about that. The fourth is that the results are qualitative. A cross tells you a library does not work, but the remarks do not say what the failure was beyond the one mention of JNA, so you would still have to run the build yourself to understand it. And the fifth is the scope of what native image means for a Clojure application in the first place, since the benefit is a small, fast-starting binary and the cost is build time, a larger toolchain and the loss of runtime flexibility, and a compatibility table does not help with that trade. If you are not sure you want a native image at all, this project answers a question you may not have.

Editorial conclusion

Adopt the graalvm-clojure project as a checklist before you attempt a Clojure native image, since its per-library projects tell you in advance which dependencies will compile and which will not. Skip it as a library or a build template, because it is a compatibility corpus rather than a tool. Verify first which libraries you actually depend on, since the table is long and covers the common ones rather than the whole ecosystem, and read the per-library directory for the ones marked with a warning or a failure before planning around them.

Frequently asked questions

What is the graalvm-clojure project for?

It contains a set of hello world projects whose purpose is to verify which Clojure libraries do actually compile and produce native images under GraalVM. The README lists the tested libraries in a table with a status column, so you can check a dependency before attempting a native image build of your own.

Which Clojure libraries are reported as failing the GraalVM native image test?

The table marks clj-sophia, a fast RAM-Disk hybrid storage, as failing with a runtime error involving JNA, and monger, an idiomatic Clojure MongoDB driver with sane defaults, as failing with no remark. fastmath, a fast and primitive math and stats library, is marked with a warning and points at its own README. Other entries pass with caveats, such as clara-rules which requires an AOT compiled session and clj-uuid which has no objects in namespaced uuids.

How do I build my own Clojure project with GraalVM using this repository?

The README links a GraalVM download from the graalvm-ce-builds releases, a document at doc/clojure-graalvm-native-binary.md describing how to build a hello world project, and an anchor in that document covering multi-platform builds with GitHub Actions. The repository also holds a sample-project directory alongside the per-library directories used for the compatibility checks.

Official sources

  1. clj-easy/graalvm-clojure on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/clj-easy-graalvm-clojure.svg)](https://hysenlabs.com/projects/clj-easy-graalvm-clojure)

Was this useful?