For a list of breaking changes, check here.
Clj-kondo: static analyzer and linter for Clojure code that sparks joy ✨
:equals-float, warn on comparison of floating point numbers with =. This level of this linter is :off by default.nil return from if-like formsprintf to vars linted by analyze-format. (@tomdl89)if-let etc condition as always truthyif-not condition as always truthy:cljc config option. (@NoahTheDuke):redundant-nested-call for comp, concat, every-pred and some-fn since it may affect performance:redundant-ignore:config-in-ns and :discouraged-namespace:discouraged-var:redundant-nested-call (@tomdl89), set to level :info by default:redundant-ignore, :redundant-str-call linters to level :info:redundant-do in catch--report-level flagrequire and :require forms (@NoahTheDuke)gen-interface (by suppressing unresolved symbols)cond-> and cond->> (@tomdl89)str/replace and ^String annotation:redundant-ignore linter:redundant-ignore. See docsletfnhooks-api/callstack function--skip-lintdeftype and defrecord constructors can be used with Type/new:sort option to :unsorted-required-namespaces linter to enable case-sensitive sort to match other toolsgen/fmap var in cljs.spec.gen.alphabyte/1):destructured-or-binding-of-same-map which warns about
:or defaults referring to bindings of same map, which is undefined and may result in broken
behavior:analyze-call hook:as-alias with current namespace without warning about self-requiring namespace@x should warn with type error about x not being an IDeref, e.g. with @incdo and doto type checking (@yuhan0):unused-valueor without arguments--dependencies --copy-configs:discouraged-namespace can have :level per namespace.clj-kondo/imports but weren't pick up correctly. Thanks @frenchy64 for reporting the bug.:redundant-str-call which detects unnecessary str calls. Off by default.:equals-expected-position to enforce expected value to be in first (or last) position. See docs--config {:output {:format :sarif}}for expressiondefn body:flds to be used in keys destructuring for ClojureDart:discouraged-var on global JS values, like js/fetch:java-static-field-call.:shadowed-fn-param which warns on using the same parameter name twice, as in (fn [x x])String*) may occur outside of metadatabigint in CLJS is a known symbol in extend-type:java-static-field-call locally(Thread/interrupted):java-static-field-call: calling static field as function should warn, e.g. (System/err)assert in hooksdatomic-type-extensions to datalog syntax checking:exclude-files in combination with linting from stdin + provided --filename argument:macroexpand hook:unused-value using :config-in-call:not-a-function linter in reader tagns-map unmaps var defined prior in namespaceif/when condition as always truthy, e.g. (when #'some-var 1):min-clj-kondo-version in config.edn and warn when current version is too low (@snasphysicist):underscore-in-namespace (@cosineblast):condition-always-true linter, see docs:multiple-async-in-deftest linter: warn on multiple async blocks in
cljs.test/deftest, since only the first will run.deftype a var that is referred with :refer :all:line-length warnings cannot be :clj-kondo/ignored#'foo/foo and (var foo/foo) the same treatment with respect to private calls:macroexpand hook:self-requiring-namespace:equals-false, counterpart of :equals-true (@svdo):syntax check for var names starting or ending with dot (reserved by Clojure):level in :discouraged-var config:single-logical-operand linter (@wtfleming)clojure.core/parse-uuid from nilable/string to string (@dbunin):end-row and :end-col in :pattern output format (@joshgelbard):missing-else-branch--copy-configs is enabled but no config dir exists:unused-alias and namespaced map:callstack in analysis:unused-alias. See docs.clojure.set/project:lint-as clojure.core/defmacro should suppress &env as unresolved symbolclojure.core/zero? to number -> boolean:unresolved-symbol linter config contains unqualified symbol:keyword-binding linter should ignore auto-resolved keywordsthrow:exclude option to :deprecated-namespace linterdata_readers.clj(c):unused-refeferred-var linterclj-kondo.hooks-api interpreter namespace:case-symbol-test:quoted-case-test-constant to :case-quoted-test:duplicate-case-test-constant to :case-duplicate-test:unsorted imports:deprecated-namespace linterdefprotocol metadata (@lread).cljd files when linting (@ericdallo)if-some + recurjava.util.List type hint corresponds to :list or nil:arglists metadata to :arglist-strs for analysis data (@lread):redundant-fn-wrapper in CLJS when passing keyword to JSclj-kondo.hooks-api/*reload* to true does not lint with the latest hook changes._ should not be reported as unused#?(:clj 1 2) (2 is not a keyword):missing-test-assertion introduced in 2023.05.18:refers to :refer-all findingswap!:uninitialized-var moved from default :level :off to :warning:equals-true: suggest using (true? x) over (= true x) (defaults to :level :off).:plus-one and :minus-one: suggest using (inc x) over (+ x 1) (and similarly for dec and -, defaults to :level :off):unresolved-namespace :exclude as already required namespaces--debug is true#() and #"" in .edn files:sha instead of :git/sha in combination with git url in deps.edn:defined-by->lint-as key which contains the :lint-as value for "defining" var, whereas :defined-as now always contains the name of the original "defining var". This is a BREAKING change..java files.:or default in :local-usages analysisdata_readers.clj:ns-groups to be used with :analyze-call and :macroexpand hooks:keyword-binding linter:lint-as clj-kondo.lint-as/def-catch-all should ignore unresolved namespaces:missing-test-assertion cases, e.g. (deftest foo (not (= 1 2))).cljc files with :output {:langs true}. See docs.Too many arguments to def:discouraged-tag linter for discouraged tag literals. See the docs.:gen support on clojure.spec.alpha/keys:exclude-patterns in :unresolved-symbol linter:def-fn on def + reify:unresolved-namespace linter:symbols + :aliased-namespace-symbol linter gives false positive in quoted symbol:exclude-pattern in :unused-bindingschema.core/defn with invalid s-exprs{:ignore [:unresolved-symbol]} or {:ignore true}, valid in ns-metadata, :config-in-ns, :config-in-call:var-same-name-except-case linter: warn when vars have names that differ only in case (important for AOT compilation and case-insensitive filesystems) (@emlyn).:jvm-opts in top level of deps.ednupdate, update-in, swap!, swap-vals!, send, send-off, and send-via (@jakemcc).java-member-definitions bucket (@ericdallo).hooks-api/set-node and hooks-api/set-node? (@sritchie).clojure.core/aget with more than two args:misplaced-docstring in clojure.test/deftest&) symbol in fn syntaxdef:uninitialized-var linter. See docs.hooks-api/resolve. See docs.:redundant-fn-wrapper with syntax-quoted body:dynamic-var-not-earmuffed should be opt-in:line-length linter:macroexpand:level :off in :discouraged-var config on var levelclj-kondo.lint-as/def-catch-all doesn't emit locations, fixes navigation for lsp:macroexpand hook (performance optimization)*err* in hooks:discouraged-namespace to be suppressed with #_:clj-kondo/ignore:discouraged-namespace linterdefn properly:exclude-urls and :exclude-pattern:def-fn: warn when using fn inside def, or fn inside let inside def (@andreyorst).:aliased-namespace-var-usage gives erroneous output for keywords:aliased-namespace-var-usage: warn on var usage from namespaces that were used with :as-alias. See demo.comment forms (@mk). See demo.:symbols analysis for navigation to symbols in quoted forms or EDN files. See demo.:as-aliasCLJ_KONDO_EXTRA_CONFIG_DIR environment variable to enable extra linters after project configglibc in dynamic linux binary to 2.31 by using fixed version of CircleCI image(def x :foo) (inc x) will now give a warning:duplicate-field-name linter for deftype and defrecord definitions.new analysis from (String. x) expansionnamespace-munge for resolving hook files rather than munge**, *** etc. to be a dynamic varsdefinterface as unuseddefinterface more similarly to defprotocol for lsp-navigationhooks-api/generated-node? function to check if a node was generatedre-find for ns groups rather than re-matches:earmuffed-var-not-dynamic and :dynamic-var-not-earmuffed. See docs.:exclude option to :used-underscored-binding (@staifa).cljs and .cljc for :aliased-namespace-symbol in interop calls. (@NoahTheDuke):derived-location to analysis when location is derived from parent node:level :off not being respected in :discouraged-var configs that are merged in.clojure.spec.alpha/def name positionschema.core/defrecordclj-kondo-docker pre-commit hook.:redundant-fn-wrapper support for keyword and binding calls (@NoahTheDuke):include-macros in .cljs and .cljc for :unknown-require-option linter. (@NoahTheDuke):exclude option to :unknown-require-option:unused-value by default.sha256 files along with released artifacts:unused-value - see docs. Also see issue #1258.:line-length - see docs (@ourkwest):unknown-require-option - see docs. (@NoahTheDuke):aliased-namespace-symbol - see docs. (@NoahTheDuke)nil values (@sheluchin):unused-binding config :exclude-destructured-as flag. (@NoahTheDuke)deftype in CLJS:config-in-call - see docs:config-in-tag - see docsfile-analyzed-fn, bump babashka/fs to 0.1.11(require '[]) and (import '())tag function in clj-kondo.hooks-api:filename-pattern in :ns-groupclojure.pprint/pprint to the hooks API:show-rule-name-in-message true. See example in config guide.:imported-ns in analysis of vars imported by potemkin:arglist-strs support for functions defined with fn:discouraged-namespace linter. See docs.sequence with map multi-arity transducerrecur not in tail position with core.async alt!!defrecord, deftype and definterface.cljc for just one language:macroexpand:instance-invocations analysis bucket.clj_kondo files from configs:macroexpand hooks (regression in 2022.05.27):warn-on-reflection linter. See docs.:redundant-call - warns when a function or macro call with 1 given argument returns the argument. See docs.clj-kondo.hooks-api API ns for REPL usage. See
docs.:file-analyzed-fn..pre-commit-hooks.yaml:macroexpand hook.clj_kondo hook extensionclojure.test/deftest-with-precision:keyword-binding - warns when a keyword
is used in a :keys binding vector. This linter is :off by default. See docs.:discouraged-var. See docs.:config-in-ns configuration option. See docs.:ns-groups configuration option. See docsclojure.core.match.) should
be unresolved when not in fn position:non-arg-vec-return-type-hint that warns when a return type hint is not placed on the arg vector (CLJ only). See docs.:namespace-name-mismatch by default^:replace override for nested config values--skip-lint, to skip linting while still executing other tasks like copying configuration with --copy-configs.re-findAnalysis:
:java-class-definitions and :java-class-usages. See docs.:end-row and end-col to analyze data for :namespace-definitions:protocol-implsdeftypereifyns + require:namespace-name-mismatch until further notice due to problems on Windows:defmethod true to defmethod var-usages analysis.:namespace-name-mismatch to detect when namespace name does not match file name. (@svdo):scope-end-row is missing on multi-arity fn args (@mainej):deprecated-var config in ns form metadatabb.edn (@mknoszlig):depends. (@mknoszlig):keys can be used in :ret position, also fixes types return map call as input for another typed map function. (@pfeodrippe)#(inc %). See
docs. This linter of :off by default
but may be enabled by default in future versions after more testing.bb.edn (@mknoszlig)recur in cond-> gives warning about recur not in tail position.:conflicting-fn-arity: warn when an arity occurs more than once in a function that overloads on arity. #1136 (@mknoszlig):clj-kondo-config which provides linting for .clj-kondo/config.edn. #1527:reduce-without-init for functions known to be safe #1519fdef can be arbitrary namespace #1532:output {:progress true} should print to stderr #1523--debug is enabled. #1514:reduce-without-init: warn against two argument version of
reduce. Disabled by
default. See docs. #1064 (@mknoszlig):quoted-case-test-constant: warn on quoted test constants in case. #1496 (@mknoszlig).clj-kondo/*/*/config.edn. This can be disabled with :auto-load-configs false. #1492:duplicate-case-test-constant: detect duplicate case test constants. See docs. #587 (@mknoszlig):unexpected-recur: warn on recur in unexpected (non-tail) position. #1126:used-underscored-binding: warn on used bindings that start with underscore. Disabled by default. See docs. #1149 (@mknoszlig):docstring-blank for checking empty docstring. See docs. #805 (@joodie):docstring-leading-trailing-whitespace for checking leading and trailing whitespace in docstring. Disabled by default. See docs. #805 (@joodie):docstring-no-summary for checking the absence of summary of args in docstring. Disabled by default. See docs. #805 (@joodie):exclude-defmulti-args option for :unused-bindings linter. See docs. #1188 (@mknoszlig):config-in-comment #1473. See docs.clojure.data.json:refer suggestion so you can copy paste it #1293 (@vemv)extend-protocol, extend-type, reify, specify! #1333, #1447:context in nodes in hooks for adding context to analysis #1211goog.object, goog.string etc must be required before use in newer releases
of CLJS #1422(exists? foo.bar/az) complains about require #1472gen-class if namespace has -main fn
#1417. See docs.def #1408def + fn combination
#1410fn type inference
#1412rseq called on other type than vector or sorted-map now gives type error #1432.cljc #1403:from-var in higher order call #1404:duplicate-ns to duplicate-require linter output #1421 (@ericdallo)if-let / if-some with invalid arity no longer warn #1426import-vars #1385case to avoid false positives for constants #1388ns-unmap pattern #1384:end-row, :end-col to :var-usages analysis element #1387:row and :col for :var-usages to use the start location of the call instead of the name location #1387:as-alias (new feature in Clojure 1.11) #1378:loop-without-recuir wrt/ fn and other constructs that introduce a recur target #1376:loop-without-recur linter. #426deps.edn and bb.edn :paths #1353 (@lread):refer to var-usages when inside a require #1364 (@ericdallo)babashka.process/$ #1368defmulti #1310ns-analysis fn in hooks API #1349 (@hugoduncan)reg-finding! #1344 (@ericdallo)declare name positions in analysis #1343 (@ericdallo)deps.edn to match Clojure CLI 1.10.1.933 (@dpassen):macroexpand hook. This allows linting using the same or similar macros from
your code. See
docs.ex-info #1314map, filter, reduce, etc.) #1297map-node and map-node? to hooks API #1270:skip-comments false doesn't override :skip-comments true in namespace config #1295clojure.spec/keys #1289clojure.spec.alpha/keys #1272 (@daveduthie)clojure.template/do-template #603clojure.test/are #1284clojure.data.xml imported via macro #1274([]) as invalid call to vector #1276:doc from attr-map in defn #1265.jar files with --dependencies when config(s) have changed #1285--fail-level flag to specify the minimum severity for a non-zero exit code #1259 (@RickMoynihan)core.async defblockingop macro #1244:or map #1242:defined-by contains raw node for sgen fns #1231:report-duplicates linter config for several linters. #1232 (@snoe)--copy-configs flag to indicate copy configs from dependencies while linting. This replaces --no-warnings.--dependencies flag to indicate skipping already linted jars for performance. This replaces --no-warnings.user.clj #1190sgen/lazy-prims #1192:lint-as with cond-> #1205clojure.core.reducers/defcurried #1217:defined-by on missing var definitions #1219 (@ericdallo):unused-private-var warning for deftype ^:private #1222:exclude config to :refer linter #1172:refer #546clojure.data.xml/alias-uri#1180Thanks to @snoe and @ericdallo for contributing to this release. Thanks to the sponsors on Github, OpenCollective and Clojurists Together for making this release possible.
:aliases to ns ctx and :alias to var-usages #1133 (@snoe):end-row and :end-col to var-definitions bucket on analysis #1147 (@ericdallo)clojure.spec.gen.alpha/fmap #1157Thanks to @SevereOverfl0w, @jysandy, @tomdl89, @snoe, @audriu, and @ericdallo for contributing to this release.
:unresolved-var. This detects unresolved vars in other namespaces, like set/onion. See docs. #635lint-specific-calls! #1116 (@tomdl89)and and or #1122 (@tomdl89):ns to :unused-namespace findings (@ericdallo):refer-clojure + :only #957deftype and defrecord #140cljs.core/simple-benchmark syntax #1079babashka.process/$ macro syntax #1089refer :all when linting in parallel #1068amap #1069deps.edn causes false positive #1093deps.edn #1094Thanks @bennyandresen, @jaihindhreddy, @mharju, @pepijn, @slipset and @nvuillam for contributing to this release. Thanks to Clojurists Together for sponsoring this release.
--filename option to set filename when linting from stdin. This should be
used for editor plugins to enable deps.edn linting.--no-warnings flag to indicate linting is used to populate cache.:include option for shadowed-var linter #1040:files count in summary #1046:all
#1010format #1044Thanks @zilti, @dharrigan and @sogaiu for contributing to this release. Thanks to Clojurists Together for sponsoring this release.
:as binding
clj-kondo#1016 (@dharrigan)contains? #1021let and do in hook-generated code #1038(or) #1023Thanks to @cldwalker, @bfontaine, @snoe, @andreyorst, @jeroenvandijk, @jaihindhreddy, @sittim and @sogaiu for contributing to this release. Thanks to the people who helped designing the new features in Github issue conversations. Thanks to Clojurists Together for sponsoring this release.
Add --parallel option to lint sources in parallel. This will speed up
linting an entire classpath. #632, #972
Detect error when calling a local that's not a function. #948
(let [inc "foo"]
(inc 1))
^--- String cannot be called as a function
Support ignore hints #872:
(inc 1 2 3)
^--- clojure.core/inc is called with 3 args but expects 1
#_:clj-kondo/ignore
(inc 1 2 3)
^--- arity warning ignored
#_{:clj-kondo/ignore[:invalid-arity]}
(do (inc 1 2 3))
^--- only redundant do is reported, but invalid arity is ignored
Also see config.md.
Merge config from $HOME/.config/clj-kondo, respecting XDG_CONFIG_HOME. See
config.md for details. #992
New :config-paths option in <project>/.clj-kondo/config.edn. This allows
extra configuration directories to be merged in. See
config.md for details. #992
Config tool that can spit out library
specific configurations that can be added via :config-paths. Contributions
for libraries are welcome.
Experimental spec inspection tool that attempts to extract type information for linting. Also uses the new :config-paths feature.
Allow pinned version in installation script #946 (@cldwalker)
defc hook #960into and transducer #952native-image build @jaihindhreddyDetails about releases prior to v2020.09.09 can be found here.
:defined-by->lint-as key which contains the :lint-as value for "defining" var, whereas :defined-as now always contains the name of the original "defining var". This is a BREAKING change.:row and :col for :var-usages to use the start location of the call instead of the name location #1387Can you improve this documentation? These fine people already did:
Michiel Borkent, Eric Dallo, Noah, mknoszlig, Tom Dalziel, Lee Read, Sam Umbach, Alex Sheluchin, Jacob Maine, André Ribeiro Camargo, Kirill Chernyshov, Renan Ribeiro, Artur Dumchev, Stefan van den Oord, Martin Kavalar, Jake McCrary, Joni Hämäläinen, Sebastian Andersen, Jacob Taylor-Hindle, Emlyn Corrin, yuhan0, Chance Russell, allie-jo, Joel Hess, Scott N A Smith, Vipin Nair, Ryan Schmukler, Wes Morgan, staifa, Dmytro Bunin, Iñaki Arenaza, ikappaki, Joshua Suskalo, Rick Moynihan, James Croft, Derek Passen, Pedro Girardi, Gian, Stig Brautaset, Rachel Westmacott, Klay, Sam Ritchie, Will Fleming, Yurii Hryhorenko, Josh Gelbard, Jakub Dundalek, Inge Solvoll, Magnar Sveen, Rahuλ Dé & Juho TeperiEdit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |