Table of Contents
Préambule
Most of the time, you can configure Neovim painlessly with a simple vim.lsp.enable("some_lsp_server"). And boom, autocompletion, go to definition. Everything works out of the box. But that’s not the case with Java, you can’t check the definition of classes from the java, javafx or whatever package that is outside of your project, and most of the time the language server takes forever to load up or simply doesn’t start.
To fix these issues, we will not enable jdtls from the vim.lsp.enable function, and we will use the mfussenegger/nvim-jdtls plugin.
In this tutorial, I assume that you know how to download plugins and edit you init.lua file. You should also already have a completion plugin.
Versions
I think that the version of python, jdtls and nvim might affect the accuracy of this tutorial. So I will give you the versions I use as a reference in case you encounter some bugs.
% nvim --version
NVIM v0.11.6
Build type: RelWithDebInfo
LuaJIT 2.1.1767980792
# jdtls
jdt-language-server-1.55.0-202601131729.tar.gz
% python3 --version
Python 3.14.3
% java --version
openjdk 25.0.2 2026-01-20
Downloading Java and jdtls
Java
First of all, you should install OpenJDK. You should download the latest version (at the time being it’s version 25, but 21 should work).
jdtls with pacman
If you use pacman on your Linux distro it’s really easy. Just build the AUR package :
git clone https://aur.archlinux.org/jdtls.git
cd jdtls/
makepkg -si
jdtls without pacman
On other distros, I do not know how to install jdtls with the ‘official’ way. I know you could download it with the mason.nvim plugin, but it will make you go through additional configuration steps. I prefer downloading jdtls and adding it to my $PATH myself.
So first of all download the latest tarball.
baseurl="https://download.eclipse.org/jdtls/milestones"
ver=$(
curl -s "$baseurl/" |
grep -oE '/jdtls/milestones/[0-9]+\.[0-9]+\.[0-9]+' |
awk -F/ '{print $4}' |
sort -V |
tail -n1
)
file=$(
curl -s "$baseurl/$ver/" |
grep -oE "jdt-language-server-${ver}-[0-9]+\.tar\.gz" |
head -n1
)
curl -fL "https://www.eclipse.org/downloads/download.php?file=/jdtls/milestones/1.56.0/$file" -o jdtls.tar.gz
You should now have a jdtls.tar.gz file in your current working directory. Do not untar it now.
Next create those folders :
sudo mkdir -pv /usr/local/share/java/jdtls
And you can now extract the content of jdtls.tar.gz into /usr/local/share/java/jdtls.
sudo tar xf jdtls.tar.gz -C /usr/local/share/java/jdtls
Next create a symlink to the jdtls binary in your $PATH :
sudo ln -s --relative /usr/local/share/java/jdtls/bin/jdtls /usr/local/bin/jdtls
You have successfully installed jdtls !
Configuring Neovim
First of all, install the mfussenegger/nvim-jdtls plugin with your neovim plugin manager.
Then, DO NOT enable jdtls with the vim.lsp.enable function.
Instead, append this at the end of your init.lua file.
vim.api.nvim_create_autocmd("FileType", {
pattern = "java",
callback = function(args)
local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ":p:h:t")
local workspace_dir = vim.fn.stdpath("data") ..
package.config:sub(1, 1) .. "jdtls-workspace" .. package.config:sub(1, 1) .. project_name
local config = {
name = "jdtls",
cmd = {
"jdtls",
"-data",
workspace_dir,
},
root_dir = vim.fs.root(0, { ".git", "gradlew", "mvnw" }),
-- Here you can configure eclipse.jdt.ls specific settings
-- See https://github.com/eclipse/eclipse.jdt.ls/wiki/Running-the-JAVA-LS-server-from-the-command-line#initialize-request
-- for a list of options
settings = {
java = {
}
},
-- This sets the `initializationOptions` sent to the language server
-- If you plan on using additional eclipse.jdt.ls plugins like java-debug
-- you'll need to set the `bundles`
--
-- See https://codeberg.org/mfussenegger/nvim-jdtls#java-debug-installation
--
-- If you don't plan on any eclipse.jdt.ls plugins you can remove this
init_options = {
bundles = {}
},
}
require('jdtls').start_or_attach(config)
end
})
Now, if you restart Neovim, and open a Java file in a project that has a .git, mvnw, or gradlew file at the top level directory. jdtls should work out of the box and you will be able to use all it’s lsp features.