Skip to content
A linter for Clojure code that sparks joy.
Clojure Shell Other
Branch: master
Clone or download
Latest commit 910817d Aug 22, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci [#414] save uberjar artifact Aug 9, 2019
.clj-kondo [#373] output analysis info Jul 31, 2019
.github doc Aug 15, 2019
analysis Update Aug 2, 2019
corpus [#422] fix recur arity false positive with core.async/alt Aug 18, 2019
doc doc: fix typo (#429) Aug 22, 2019
extract/clj_kondo/impl [#338] warn on deprecated var usage Jul 15, 2019
inlined/clj_kondo/impl/toolsreader/v1v2v2 Update for cljdoc Jun 29, 2019
logo snap package Jul 9, 2019
parser/clj_kondo/impl/rewrite_clj [#314] rewrite parsing of metadata Jul 1, 2019
resources bump version Aug 21, 2019
screenshots [#342, #229] add warning for refer :all, but when it is used, resolve… Jul 24, 2019
script Support PATH native-image on *nix-likes Aug 5, 2019
src/clj_kondo [#406] automatically enable cache when .clj-kondo dir is detected Aug 21, 2019
test/clj_kondo [#406] automatically enable cache when .clj-kondo dir is detected Aug 21, 2019
.gitignore [#394] fix crash when dir has source-file? extension Aug 4, 2019
Dockerfile [#410] fix docker build issue (#411) Aug 8, 2019
LICENSE initial commit Mar 20, 2019 Fix small typo in README (#428) Aug 22, 2019
appveyor.yml [#355] upgrade to GraalVM 19.1.1 Jul 18, 2019
deps.edn [#373] output analysis info Jul 31, 2019
project.clj [#373] output analysis info Jul 31, 2019
reflection.json upgrade to GraalVM 19 (#158) May 12, 2019
snapcraft.yaml bump versions Jul 31, 2019

CircleCI Build status Clojars Project cljdoc badge project chat

A 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 do and let nestings don't really add any value to your life. Let clj-kondo help you tidy your code.


clj-kondo detects:

  • inline def expressions
  • redundant do and let wrappings
  • arity errors:
    • within the same namespace and across namespaces
    • of static Java method calls
    • of local let and letfn binding calls
    • of recursive calls (including recur)
  • private and deprecated var usage
  • required but unused namespaces
  • referred but unused vars
  • duplicate requires
  • unused function arguments and let bindings
  • redefined vars
  • unresolved symbols
  • misplaced docstrings
  • duplicate map keys and set elements
  • missing map keys
  • invalid number of forms in binding vectors
  • missing assertions in clojure.test/deftest

before your REPL knows it.

It suggests several style guide recommendations, such as:

It has support for syntax of commonly used macros like clojure.core.async/alt!!, schema.core/defn and potemkin/import-vars.

It provides analysis data so you build your own custom linters.

This linter is:

  • compatible with .clj, .cljs, .cljc and .edn files
  • build tool and editor agnostic
  • a static code analyzer
  • compiled to native code using GraalVM

Try clj-kondo at the interactive playground.


Running on the JVM

Running with Docker


Command line

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)"

Project setup

To detect lint errors across namespaces in your project, a cache is needed. To let clj-kondo know where to create one, make a .clj-kondo directory in the root of your project, meaning on the same level as your project.clj, deps.edn or build.boot. A cache will be created inside of it when you run clj-kondo. 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>"

Build tool specific ways to get a classpath:

  • lein classpath
  • boot with-cp -w -f
  • clojure -Spath

So for lein the entire command would be:

$ clj-kondo --lint "$(lein classpath)"

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 --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.

If you want to use a different directory to read and write the cache, use the --cache-dir option. To disable the cache even if you have a .clj-kondo directory, use --cache false.


Editor integration

Exit codes

  • 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.

Analysis data



Building from source

Thanks to:

Support this project

Do you enjoy this project? Consider buying me a hot beverage.


Copyright © 2019 Michiel Borkent

Distributed under the EPL License, same as Clojure. See LICENSE.

The directory inlined contains source from tools.reader which is licensed under the EPL license.

The directory parser contains modified source from rewrite-clj which is licensed under the MIT license.

You can’t perform that action at this time.