- Published on
Native Autocompletion and Simpler LSP Configuration in Neovim 0.11
- Authors

- Name
- Kiet
With the recent release of Neovim version 0.11, aside from performance improvements in Treesitter, LSP diagnostic lines, and more, perhaps the most anticipated feature (at least for me) is the built-in auto-completion and the new way to set up LSP without requiring the lspconfig.nvim plugin.
However, don't misunderstand—there's no need to change your current configuration to adapt to these updates. Your existing LSP configurations will continue to work as usual, and using lspconfig.nvim remains perfectly fine. But for someone like me, who enjoys exploring and comparing different approaches, I decided to try replacing my setup and using these new features in both my work and personal projects. This blog post will detail how I configured everything, compare the differences, and share my personal decision. Hopefully, this will help you decide whether updating your Neovim configuration is necessary.
What's new?
Built-in Auto-completion
If you've been a long-time Neovim user, you're probably familiar with omnifunc and how challenging it was to set up auto-completion in the past. As someone who has used Neovim since the days of configuring with CoC, then moving to cmp-nvim, and recently migrating to blink.nvim, I can relate to the frustration of making auto-completion work seamlessly, like in modern IDEs such as Visual Studio Code or IntelliJ. Recognizing this challenge, the Neovim team has actively added this feature in version 0.11.
Simpler LSP Config
Previously, setting up LSP often involved using lspconfig.nvim (though it wasn't strictly required). Now, with two new interfaces—vim.lsp.config and vim.lsp.enable—you can configure LSP without needing the lspconfig plugin. Additionally, the Neovim team has introduced a folder structure (*lsp/***) for creating configuration files for each LSP server, making the setup process more straightforward and organized.
How to setup?
Enable LSP Server When Opening a Buffer
First, you need to tell Neovim which LSP servers to enable when opening a buffer. This is straightforward with the vim.lsp.enable API mentioned earlier. You can pass one or more LSP servers as parameters to the function. Here's an example with the lua-language-server. Note that the LSP client name here can be customized, but it must match the file name mentioned in the next step.
In the file: init.lua, add the following code:
vim.lsp.enable({
"lua_ls",
})
Create lsp client config file
Next, you need to create a configuration file for the corresponding LSP. Create a file named lsp/lua_ls.lua, where lua_ls matches the LSP client enabled in the previous step. Your folder structure should look like this:
├── init.lua
└── lsp
└── lua_ls.lua
Similarly, you can enable multiple LSP clients.
What About the Config File Content
You might wonder what the content of the client config file should be. Unlike using the lspconfig.nvim plugin, where default values are provided, you'll need to manually add configurations to the lsp/lua_ls.lua file you created earlier.
return {
cmd = { 'lua-language-server' },
filetypes = { 'lua' },
root_markers = {
'.luarc.json',
'.luarc.jsonc',
'.luacheckrc',
'.stylua.toml',
'stylua.toml',
'selene.toml',
'selene.yml',
'.git',
},
}
The content of this config file is concise and self-explanatory. However, if you'd like to learn more about these settings, refer to :h lsp-quickstart. If you're curious about where these configurations come from, the answer is the lspconfig.nvim repository. You can copy the LSP configs you need from there.
Built-in Auto-completion (Optional)
After successfully configuring LSP, you can use omnifunc with the shortcut <C-X><C-O> to trigger completion manually. However, if you want auto-completion, you can enable the built-in auto-completion feature introduced in version 0.11 without installing any additional plugins using the following code:
In the file: init.lua, add the following code:
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(ev)
local client = vim.lsp.get_client_by_id(ev.data.client_id)
if client:supports_method('textDocument/completion') then
vim.lsp.completion.enable(true, client.id, ev.buf, { autotrigger = true })
end
end,
})
This code is fairly self-explanatory. With autotrigger = true, auto-completion will be triggered when you type characters defined by the LSP server's trigger characters. If you'd like to customize the trigger characters, you can configure them as shown below:
vim.api.nvim_create_autocmd('LspAttach', {
callback = function(ev)
local client = vim.lsp.get_client_by_id(ev.data.client_id)
if client:supports_method('textDocument/completion') then
client.server_capabilities.completionProvider.triggerCharacters = vim.split(".abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ(", "", { plain = true })
vim.lsp.completion.enable(true, client.id, ev.buf, { autotrigger = true })
end
end,
})
Personally, I prefer triggering code completion only when I need it.
My opinions
- If you want to use the new configuration method in version 0.11 to remove lspconfig.nvim from your plugin list, consider whether you're willing to maintain these configuration files yourself. If you're only using simple LSP servers like lua-language-server, the new method is viable. However, for more complex LSP configurations like sourcekit-lsp or eslint-lsp, you'll need utility functions like
root_patternto make them work. - If you're satisfied with the default settings of these LSP servers, the wise choice would be to let lspconfig.nvim handle them for you.
- Personally, I believe understanding LSP configurations helps me optimize and understand the limitations of what LSP servers can support during development. While it's worth the effort, it can be a significant challenge for someone who works with multiple programming languages like me.
- Although version 0.11 introduces built-in auto-completion, I noticed during my experience that some features provided by other auto-completion plugins come for free without additional setup. For example, to use
completeopt+=popup, you need to handle it on the client side if the LSP server doesn't support it. You can refer to the source code here. However, after successfully setting it up, I realized I didn't need it and removedpopupfrom mycompleteopt.
Conclusion
With version 0.11, it's clear that Neovim is becoming more polished and is moving towards simplifying its notoriously challenging setup process. I am particularly impressed by the Neovim community and the contributions of its veteran contributors. I hope that one day I will have the time to give back to this amazing community.