What is ClojureDart?
ClojureDart is a recent Clojure dialect to make native mobile and desktop apps using Flutter and the Dart ecosystem.
It's production-ready: applications are being built with it.
Funding and Support
ClojureDart is developed by Baptiste Dupuch🐦 and Christophe Grand🐦 by taking time off of their consultancy -- it's grueling at times.
How can you help?
- Sponsor us (individual sponsorship is nice but corporate sponshorship is great). You can sponsor any of us or both, it doesn't matter, we split (❤️ Baptiste ❤️ Christophe).
- Contract us for assistance, training, consulting or dev (can be as mundane as requesting to port a clj/cljs lib to cljd)
Cheatsheet
We have a cheatsheet covering ClojureDart specifics on one side and Flutter programming on the other side.
Conj 2025 talk and repl demo
Our 2025 progress report featuring the repl and maps improvements.
Conj 2023 talk and demo
Want to see what's the workflow like? Our talk at Clojure/Conj 2023 is mostly a live-coding session, starting from scratch and assuming no prior knowledge of Dart or Flutter! Click here or on the image 👇
Where to find help?
Stop by the Clojurians #ClojureDart channel or open an issue.
Completeness Status
- REPL: beta, clojure.repl (
doc,apropos...) not ported. - multimethods: partial (no hierarchies or type system support).
Links dump
Don't forget to subscribe to Curiosities -- our newsletter on ClojureDart and more!
Your first app!
Prerequisites: Clojure and Flutter installed and on your path.
Create a project directory with its deps.edn
mkdir hello cd hello cat << EOF > deps.edn {:paths ["src"] ; where your cljd files are :deps {tensegritics/clojuredart {:git/url "https://github.com/tensegritics/ClojureDart.git" :sha "81b5c03a55cf52b21dc0be8ccfa4827b9889f488"}} :aliases {:cljd {:main-opts ["-m" "cljd.build"]}} :cljd/opts {:kind :flutter :main acme.main}} EOF
(To update an existing project to the latest ClojureDart, just do clj -M:cljd upgrade)
Initialize project:
Add some source code:
mkdir -p src/acme cat << EOF > src/acme/main.cljd (ns acme.main (:require ["package:flutter/material.dart" :as m] [cljd.flutter :as f])) (defn main [] (f/run (m/MaterialApp .title "Welcome to Flutter" .theme (m/ThemeData .primarySwatch m.Colors/pink)) .home (m/Scaffold .appBar (m/AppBar .title (m/Text "Welcome to ClojureDart"))) .body m/Center (m/Text "Let's get coding!" .style (m/TextStyle .color m.Colors/red .fontSize 32.0)))) EOF
Compile, watch and run:
In most environments this will spawn a desktop app.
More details there
Quick starts
- For Flutter to build GUIs
- For Plain Dart to build CLI apps.
Examples
In the samples directory, you'll find original sample code and ports of Flutter recipes.
How to run a sample project
Clone the ClojureDart repo.
git clone https://github.com/Tensegritics/ClojureDart.git
Go to the sample you want to try, let's say fab:
cd ClojureDart/samples/fabInit the project:
Then launch the watcher:
You should get the sample running either in Chrome or as a desktop app.
To specify your exact target you must run flutter devices which outputs something like:
3 connected devices: iPhone 6s (mobile) • D6707352-78D2-46BB-AB95-87355283FC82 • ios • com.apple.CoreSimulator.SimRuntime.iOS-15-5 (simulator) macOS (desktop) • macos • darwin-arm64 • macOS 12.4 21F79 darwin-arm Chrome (web) • chrome • web-javascript • Google Chrome 103.0.5060.114
The second column is the id of the target (here D6707352-78D2-46BB-AB95-87355283FC82, macos or chrome) that you pass to the watcher:
clj -M:cljd flutter -d D6707352-78D2-46BB-AB95-87355283FC82
Enjoy! 🧃
REPL (beta)
After running clj -M:cljd flutter, a line like
🤫 ClojureDart REPL listening on port 59268
will appear. Use this port to connect to a socket repl (not nrepl).
You can use nc localhost 59268 or, in inferior-lisp in Emacs by passing it a custom runner (C-U M-x inferior-lisp) then nc localhost 59268.
In addition to *1, *2, *3 and *e, there's a *env var, only bound after using cljd.flutter.repl/pick! (referred by default in cljd.user).
*env gives you access to all lexical bindings for the selected widget and to its build context, try (keys *env) to get an overview.
cljd.flutter.repl/mount! (also referred by default in cljd.user) replaces the selected widget by its argument and puts the replaced widget in *1.
You can change namespaces using ns but if the namespace already exists all the requires will be ignored and the sole effect of the ns form will be to switch namespace.
Since the REPL relies on the Dart hot reload mechanism, evaluation can be sometimes laggy. It depends mostly on the namespace you are in and its place in the dependency graph. We are working on improving that.
cljd.flutter
cljd.flutter is an utility namespace to remove Flutter boilerplate and integrate more nicely with Clojure.
cljd.flutter.alpha
Deprecated, use cljd.flutter.
cljd.flutter.alpha2
Got out of alpha status and lives a happy life as cljd.flutter.
Thanks!
To all individuals who blindly believed in our endeavor and sponsored our work.
To NuBank who approached us very early for sponsorship.
To Roam Research who bet their mobile apps development (now in the App Store and Play Store) on ClojureDart and allowed us to make steady progress since Summer 2021.
If you want to sponsor our work, you can sponsor either of us, we'll balance sponsorship. If you are a company you can also contact us directly.


