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:
(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
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: