A minimal and opinionated linter for Clojure code that sparks joy.
You don't mind the occasional inline def for debugging, but you would like to get rid of them before making your code public. Also, unnecessary
let nestings don't really add any value to your life. Let clj-kondo help you tidy your code.
- arity errors:
- within the same namespace and across namespaces
- of static Java method calls
- of local
letfn binding calls
- of recursive calls (including
- private function calls
- required but unused namespaces
- unused function arguments and let bindings
- redefined vars
- unresolved symbols
- duplicate map keys and set elements
- missing map keys
- invalid number of forms in binding vectors
- missing assertions in
before your REPL knows it.
It suggests style guide recommendations:
:else as the catch-all test expression in
cond (see style guide)
This linter is:
- compatible with
- build tool and editor agnostic
- a static code analyzer
- compiled to native code using GraalVM
Try clj-kondo at the interactive playground.
Under active development, but already useful. None of the code is meant to be exposed as a public API, except the command line interface.
For new features I'd like to focus on things that joker doesn't support yet, so I recommend enabling that one as well.
Lint from stdin:
$ echo '(def x (def x 1))' | clj-kondo --lint -
<stdin>:1:8: warning: inline def
Lint a file:
$ echo '(def x (def x 1))' > /tmp/foo.clj
$ clj-kondo --lint /tmp/foo.clj
/tmp/foo.clj:1:8: warning: inline def
Lint a directory:
$ clj-kondo --lint src
src/clj_kondo/test.cljs:7:1: warning: redundant do
src/clj_kondo/calls.clj:291:3: error: Wrong number of args (1) passed to clj-kondo.calls/analyze-calls
Lint a project classpath:
$ clj-kondo --lint "$(lein classpath)"
To detect lint errors across namespaces in your project, a cache is needed. To create one, make a
.clj-kondo directory in the root of your project. A cache will be created inside of it when you run
clj-kondo with the
--cache option. Before linting inside your editor, it is recommended to lint the entire classpath to teach
clj-kondo about all the libraries you are using, including Clojure and/or ClojureScript itself:
$ clj-kondo --lint "<classpath>" --cache
Build tool specific ways to get a classpath:
boot with-cp -w -f
lein the entire command would be:
$ clj-kondo --lint "$(lein classpath)" --cache
Now you are ready to lint single files using editor integration. A simulation of what happens when you edit a file in your editor:
$ echo '(select-keys)' | clj-kondo --lang cljs --cache --lint -
<stdin>:1:1: error: Wrong number of args (0) passed to cljs.core/select-keys
Since clj-kondo now knows about your version of ClojureScript via the cache, it detects that the number of arguments you passed to
select-keys is invalid. Each time you edit a file, the cache is incrementally updated, so clj-kondo is informed about new functions you just wrote.
0: no errors or warnings were found
2: more than one warning was found
3: more than one error was found
All other error codes indicate an unexpected error.
This project is inspired by joker. It uses clj.native-image for compiling the project. The parsing of Clojure code relies on rewrite-clj. It uses
var-info.edn and some ideas from eastwood.
Copyright © 2019 Michiel Borkent
Distributed under the EPL License, same as Clojure. See LICENSE.