cljfmt: a formatter that repairs Clojure code without rewriting it
A tool for formatting Clojure code
At a glance
- What is it?
- cljfmt detects and fixes formatting errors in Clojure and ClojureScript, deliberately avoiding a one-to-one mapping between a syntax tree and formatted text so that the diff it produces stays small. It suits a team that wants a checkable formatting rule in CI, and the indents configuration is the part that takes real thought.
- Who is it for?
- Adopt cljfmt if you want a formatting check that produces minimal diffs and refuses to reformat code it does not understand, since the whole design goal is correcting errors rather than regenerating source. Skip it if you want a full pretty-printer, since the README points at zprint for completely unstructured Clojure code.
- Can I use it commercially?
- Yes, with conditions. EPL-1.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 1 day 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The design goal, and the alternative it points to
cljfmt is a tool for detecting and fixing formatting errors in Clojure code, and its defaults are based on the Clojure Style Guide, with many customization options to suit a particular project or team. The sentence that defines the project is the one about what it is not the goal to provide. It is not the goal of the project to provide a one-to-one mapping between a Clojure syntax tree and formatted text, and rather the intent is to correct formatting errors with minimal changes to the existing structure of the text. That is a meaningful difference from a pretty-printer. A pretty-printer parses to a tree and regenerates, which guarantees canonical output and also produces a large diff the first time you run it. cljfmt only fixes what it recognises as wrong, so a file it does not understand comes out as it went in. The README names the alternative explicitly, saying that if you want to format completely unstructured Clojure code the zprint project may be more suitable.
The indents configuration, which is the hard part
The `--indents` and `--alias-map` keys were removed from the CLI in the 0.11.x breaking changes in favour of a configuration file, and the `:indents` key was then split into `:indents` and `:extra-indents`. The distinction is the one to get right. The `:indents` key replaces all default indents, while `:extra-indents` appends to the default indents. That sounds like a small distinction and it is a large one in practice, because replacing the defaults means you are now responsible for every indentation rule in the language, and a missing entry is a formatting bug. If you need to retain backward compatibility with an older version of cljfmt, you can add the `:legacy/merge-indents?` key to your configuration, and the effect is to treat `:indents` as if it were `:extra-indents`:
{:legacy/merge-indents? true
:indents {example.core/foo [[:inner 0]]}}The equivalent modern form is the same map under `:extra-indents`.
The standalone install, and the check and fix commands
The fastest way to run cljfmt is via a precompiled binary, and on Linux or MacOS the install puts it in `/usr/local/bin`:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/weavejester/cljfmt/HEAD/install.sh)"The same command updates an existing installation. Homebrew is the alternative, and the README is emphatic that if you use it you should use the `weavejester/brew` tap, since it will be much more performant than the Homebrew core package:
brew install weavejester/brew/cljfmtOn Windows there is a zipped binary to download and extract by hand. Once installed, the two commands are `cljfmt check` to look for formatting errors in a project and `cljfmt fix` to correct them, with `--help` for the full list of options.
The build tool integrations, and the same two commands
What makes cljfmt usable in an existing project is that the same check and fix pair is exposed through every Clojure build tool. As a Clojure Tools installation it is registered as a tool with `clj -Ttools install io.github.weavejester/cljfmt '{:git/tag "0.16.6"}' :as cljfmt`, and then run as `clj -Tcljfmt check` or `clj -Tcljfmt fix`. Leiningen gets a plugin added to `project.clj`, `:plugins [[dev.weavejester/lein-cljfmt "0.16.6"]]`, and then `lein cljfmt check` or `lein cljfmt fix`, with configuration in a `:cljfmt` key in the project map. Babashka is supported too, as a library or as a task defined in `bb.edn` that requires `cljfmt.tool` and calls `fmt/check`. The consistency across all four entry points is what makes it plausible to put the check in CI without special-casing the build tool.
The library API, and the trap in using it
cljfmt can also be used as a library that formats a string of Clojure code or recursively checks and fixes paths. The dependency is added as `{:deps {dev.weavejester/cljfmt {:mvn/version "0.16.6"}}}`, and formatting a string is a call to `fmt/reformat-string`, with the configuration for the current directory loaded by `cfg/load-config` when you need it. The recursive path functions are `fmt/check` and `fmt/fix`, and they come with a warning that is easy to skip. The `check` and `fix` functions assume they are running in console mode and will call `System/exit`, print to stdout and do similar things, so you must set the report function to the Clojure one, `report/clojure`, or your script will exit when it thinks it is done. That is a small API rough edge, and it is the kind of detail that turns a library into a script unless you know about it.
Configuration discovery, and the 0.16 change
In most environments cljfmt looks for its configuration in the current directory and the parent directories, and the files it looks for are `.cljfmt.edn` and `cljfmt.edn`, each containing a map of options. The 0.16.0 change is the one to know about, since only `.edn` configuration files are loaded by default now. Reading `.clj` configuration files is possible with the `--read-clj-config-files` flag, and the files that then apply are `.cljfmt.clj` and `cljfmt.clj`. If a `.clj` configuration file is detected without the flag, a warning is printed, which is the right behaviour for a change like this, since a silent switch of configuration format would be much harder to diagnose. In Leiningen the configuration lives in the `:cljfmt` key in the project map, and the `:load-config-file?` key there brings in the standard configuration file as well.
Editor integration, and where the project sits
Several Clojure editing environments have cljfmt support baked in, and the README names them. Calva for Visual Studio Code, CIDER for Emacs, clojureVSCode for Visual Studio Code and vim-cljfmt for Vim. That list is the practical reason to use this formatter over a general-purpose one, since a formatter the editor can run on save is a formatter people actually adopt. The repository layout follows the same multi-target structure, with `cljfmt/` for the library, `lein-cljfmt/` for the Leiningen plugin, `docs/`, `scripts/`, a `bb.edn` and a `deps.edn` at the root, an `install.sh` and a `update_versions.bb` script. The primary language is Clojure, the licence is EPL-1.0, and the last push was on 2026-09-24 with releases 0.16.6, 0.16.5 and 0.16.4.
Editorial conclusion
Adopt cljfmt if you want a formatting check that produces minimal diffs and refuses to reformat code it does not understand, since the whole design goal is correcting errors rather than regenerating source. Skip it if you want a full pretty-printer, since the README points at zprint for completely unstructured Clojure code. Before you adopt it, plan the `:indents` configuration, because since 0.16.0 only `.edn` configuration files are loaded by default and the `:indents` key replaces all default indents while `:extra-indents` appends to them.
Frequently asked questions
How do I install cljfmt?
As a precompiled binary with `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/weavejester/cljfmt/HEAD/install.sh)"` on Linux or MacOS, or with `brew install weavejester/brew/cljfmt`, which the README recommends over the Homebrew core package. Windows users can download the zipped binary from the releases.
What is the difference between :indents and :extra-indents?
The :indents key replaces all default indents, while :extra-indents appends to the default indents. The :legacy/merge-indents? key makes :indents behave as if it were :extra-indents, for backward compatibility with older versions of cljfmt.
How do I check and fix formatting in a Clojure project?
Run `cljfmt check` to find formatting errors and `cljfmt fix` to correct them. The same pair works through every build tool, as `clj -Tcljfmt check` and `clj -Tcljfmt fix` for Clojure Tools, and `lein cljfmt check` and `lein cljfmt fix` for Leiningen.
How do I use cljfmt as a library?
Add the dependency and require cljfmt.core, then call fmt/reformat-string on a string of code, optionally with the configuration for the current directory from cljfmt.config. For recursive path checks you must also require cljfmt.report and pass report/clojure as the report function, otherwise the functions assume console mode and call System/exit.
Official sources
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.
[](https://hysenlabs.com/projects/weavejester-cljfmt)Was this useful?