Skip to content


clojure-lsp settings are picked up on server start and can be configured via 3 ways:

  • Project configuration
  • Global configuration
  • LSP InitializationOptions


clojure-lsp will look for project specific settings in a file called .lsp/config.edn. It will search from your project root folder up the directory structure so you can have multiple projects share the same settings.


{:cljfmt {:indents {#re ".*" ns [[:inner 0] [:inner 1]]}}
 :auto-add-ns-to-new-files? false}


For global settings which should work for all the projects using clojure-lsp, you just need to add the same configs to ~/.lsp/config.edn or $XDG_CONFIG_HOME/.lsp/config.edn.

For an example of a global config.edn, check here.


This is specific for an client, where it sends on startup, check LSP spec for more information. This is useful if you are changing a default for a client/editor that will affect all users of that editor.

This is an example how Emacs lsp-mode pass custom information.

If you are using a client which defines InitializationOptions as a json object, you can use json types instead:

  • keyword -> string or colon-prefixed string ("incremental" or ":incremental")
  • map -> object ({"unused-public-ns": {"level": "info"}})
  • set -> array (["src" "test"])
  • vector -> array (["src" "test"])

All settings#

You can find all settings and its default here and below the docs for each one:

name description default
source-paths project-local directories to look for clj/cljc/cljs files, if using deps.edn, project.clj or bb.edn, use :source-aliases instead. #{"src" "test"}
source-aliases Used for deps.edn or project.clj projects, the aliases which clojure-lsp should get the source-paths besides the root level :paths and :extra-paths. Check the source-aliases discovery section below. #{:dev :test}
linters clojure-lsp custom linters, check the diagnostics settings section below
additional-snippets Additional user snippets to be available during completing, check the snippets section below []
ignore-classpath-directories will not consider clojure files within the directories specified by your classpath. This is needed, for instance, if your build puts artifacts into resources or target that you want lsp to ignore. false
lint-project-files-after-startup? Whether to async lint all project only files after startup to make features like List project errors work. true
notify-references-on-file-change Whether to update diagnostics of the changed references when editing files, avoiding outdated diagnostics in other files. false
use-metadata-for-privacy? Whether to use ^:private metadata for refactorings instead of defn- false
:clean Settings related to clean-ns refactoring. Check clean settings below.
semantic-tokens? Whether to enable LSP semantic tokens server support for syntax highlighting. true
show-docs-arity-on-same-line? Whether to keep the arity on the same line of the function on hover, useful for Emacs users. false
hover hide-file-location? Whether to show the full filename and path on hover. false
auto-add-ns-to-new-files? Whether to automatically add the ns form in new blank files. true
document-formatting? if true or not present, document formatting is provided. true
document-range-formatting? if true or not present, document range formatting is provided. true
text-document-sync-kind The sync kind during document changes, if client should send whole buffer or just related changes. Should be :full or :incremental :full
dependency-scheme How the dependencies should be linked, jar will make urls compatible with java's JarURLConnection. You can have the client make an lsp extension request of clojure/dependencyContents with the jar uri and the server will return the jar entry's contents. Similar to java clients zip
cljfmt-config-path Where to find cljfmt configuration for formatting. A path relative to project root or an absolute path. Use #re for regex inside the cljfmt configuration file. .cljfmt.edn
cljfmt If no :cljfmt-config-path is provided, used this for formatting, json encoded configuration for cljfmt {}
project-specs A vector of a map with project-path and classpath-cmd, defining how clojure-lsp should find your project classpath. the project-path should be a file and the classpath-cmd the command to run to get the classpath Check Classpath scan section below
code-lens segregate-test-references Segregate main references from test references with option to disable true
cache-path Where to store the project's analysis cache, used to speed up next clojure-lsp startup. A path relative to project root or an absolute path. .lsp/.cache
log-path A absolute path to a file where clojure-lsp should log. A JVM tmp path, usually /tmp/clojure-lsp.*.out

Classpath scan#

clojure-lsp needs to analyze the whole project and its dependencies to understand your code for most features, during the startup clojure-lsp will try to find the classpath of your project to pass to clj-kondo later.

You can configure how clojure-lsp should find the classpath with the project-specs setting, check the default here.

Supported project types at the moment are:

  • leiningen: If a project.clj is found at the project root, clojure-lsp will run lein classpath.
  • deps: If a deps.edn is found at the project root, clojure-lsp will run clojure -Spath.
  • boot: If a build.boot is found at the project root, clojure-lsp will run boot show --fake-classpath.
  • shadow-cljs: If a shadow-cljs.edn is found at the project root, clojure-lsp will run npx shadow-cljs classpath.
  • babashka: If a bb.edn is found at the project root, clojure-lsp will run bb print-deps --format classpath.

Note that it's possible to have more and one project type at the same time e.g. deps + babashka, clojure-lsp will merge the classpath and everything should works fine.

Make sure to have these programs available on the PATH environment variable used by your editor, otherwise clojure-lsp will warn about a classpath scan fail, causing a lot of features to not work properly.

Alternatively, you can configure the project-specs specific for your project, for example:


{:project-specs [{:project-path "deps.edn"
                  :classpath-cmd ["clojure" "-A:dev" "-Spath"]}]}

Diagnostics (linter)#

Default: Check :linters in all-available-settings.edn.


clojure-lsp uses clj-kondo under the hood to lint the code and retrieve the analysis to make most of features work, you don't have to install clj-kondo to make it work.

clojure-lsp will use a specific clj-kondo version that can be retrieved via clojure-lsp --version, but make sure you have it properly configured in your .clj-kondo/config.edn file.

It has the possible key/values:

  • :level with available values: :off, :on with default value of :on
  • :report-duplicates which will show all linters of the same symbol instead of showing only the first spot. Available values: true, false with default value of true
  • ns-exclude-regex which will exclude the diagnostics/findings for namespaces that match this regex.



{:linters {:clj-kondo {:level :on
                       :report-duplicates true
                       :ns-exclude-regex "some-ns.*"}}}

Note for vim users If you are a (neo)vim user and have [ale]( installed as a plugin, you **should not** have this configured as a linter `let g:ale_linters = {'clojure': ['clj-kondo']}` in your vimrc. Having this linter enabled via `ale` will only conflict with the built-in clj-kondo bundled with clojure-lsp.

For more information about all clj-kondo available configurations, check the clj-kondo configuration section

Custom clj-kondo hooks#

Clojure-lsp register custom linters in clj-kondo, for specifically those linters, configurations should be done on clj-kondo config files, e.g. (<project>/.clj-kondo/config.edn), below are the custom linters used:


A custom linter that reports public functions/vars not used over the project.

It has the possible key/values:

  • :level with available values: :info, :warning, :error or :off with default value of :info.
  • :exclude a whole namespace with #{my-ns} or a specific var #{my-ns/foo}.
  • :exclude-when-defined-by excludes this linter when your var is defined by a macro for example, like #{my-ns/deftest}.



{:linters {:clojure-lsp/unused-public-var {:level :warning
                                           :exclude #{my-ns/foo
                                           :exclude-when-defined-by #{my-ns/defflow}}}}

Disable linter#

It's not recommended to disable the linter as it provides helpful smart checks/suggestions for your code, even so it's possible via the following config:


{:linters {:clj-kondo {:level :off}}}

For information on how to troubleshoot the linter, check the troubleshooting section

Source paths discovery#

Some features require know the available source paths of your project, where your code lives, clojure-lsp has some settings for that.

  • If your project is a lein project, clojure-lsp will scan the project.clj file for :source-paths, :test-paths and the paths from the specified :source-aliases setting (default #{:dev :test}), unless you specified :source-paths manually.
  • If your project is a deps.edn, clojure-lsp will scan the deps.edn file for :paths, :extra-paths and the paths from the specified :source-aliases setting (default #{:dev :test}), unless you specified :source-paths manually.
  • If your project is not a deps.edn or lein project, a boot project for example, clojure-lsp will use only the :source-paths setting (default #{"src" "test"}) which should point to the folders containing your clojure code.


Default: Check :clean in all-available-settings.edn.


Where to place first require/import following Clojure Style Guide, :same-line, :next-line or :keep.



Whether to enable sort of ns children like require,import forms following Clojure Style Guide.


Whether to enable sort of :require form.


Whether to enable sort of :import form.


Whether to enable sort of :refer form.

  • :max-line-length: the max refers to keep at same line before breaking the line. Default 80.


Besides the 19 built-in snippets, it's possible to configure custom additional snippets via :additional-snippets setting:

  • :name the name to use while completing to reach that snippet, preferably with a $ sufix to indicate a snippet.
  • :detail Custom text to show along with the completion name.
  • :snippet The body of the snippet, besides any text it can contains:
    • $1, $2, ... as the tabstops representing each place where user may change the content.
    • $0 as the last tabstop.
    • $current-form to replace the current form in the snippet.


{:additional-snippets [{:name "wrap-let-sexpr$"
                        :detail "Wrap current sexpr in let"
                        :snippet "(let [$1] $0$current-form)"}]}

when completion is called on the code below with the cursor as |

wrap|(+ 1 2)

It should return a completion item that after applied should result in:

(let [|] (+ 1 2))

Last update: September 19, 2021