Introducing bbb - the easy way to build distributable CLI tools in Clojure with babashka and GraalVM

I’ve been spending the majority of my coding hours in Clojure lately and have really been enjoying it’s combination of brutal effectiveness, interactivity and general elegance. There’s been one thorn in my Clojure side though – it’s pretty terrible for building CLI tools and small scripts because at the end of the day Clojure is running on the JVM, and Java-based tools take an infamously long time to start.

However, after much fiddling I’ve finally managed to land on a way to make CLI tools with Clojure that’s both fun and easy to hack on, and easy for an end user to install and deploy, so I thought I’d share:

Introducing: BabashkaBins

(or bbb for short)

bbb lets you take a standard Clojure project layout, run it under both JVM Clojure and babashka, and then automates the compilation of your project into a static binary with GraalVM for you when it’s time to distribute it.

The trick to getting all this to work was to combine three lovely Clojure tools: cli-matic, babashka, and GraalVM. These three together come pretty close to the holy grail of Clojure CLI tool development. With cli-matic you can easily define complex CLI parsing logic (eg subcommands, long and short options with nicely formatted help text etc.), run it instantly with babashka during development for fast iteration and testing, and then compile it into a deployable static binary with GraalVM that can be run without any extra installation steps once you’re ready to share your creations with the world.

Getting these three tools to play together nicely was a hell of a learning experience though. I’ll be sharing everything I’ve learned about how to get them to play together in later posts, but in the meantime you can profit from my rabbit-hole spelunking by cloning the bbb repo and running git submodule init --update --recursive.

Once you have your clone (and you have GraalVM and it’s native-image tool installed) edit src/example/core.clj to do something more useful if you’d like, and then run or compile it!

You can run your project with babashka by doing:

bb -m example.core

or compile it into a distributable static binary by doing:

clj -X:native-image

More information is available in the github repo. Have fun building Clojure CLI tools and please let me know here or on twitter (@arghzero) if you build anything cool this way!