Neovim 0.12 just dropped. If you're reading this and you don't use Neovim, I'm sorry. This post won't convert you. But if you're already in the cult, pull up a chair.
I've been running 0.12 since the nightly builds stopped crashing my Lua configs every other day, and honestly? This might be the best release since 0.5 gave us native LSP. There's a ton to unpack, so let me walk you through my current setup and the features that have me mass-texting my friends who do not care.
If you're curious, have a look at my neovim dotfiles.
LSP: It Just Works Now
If you were around for the dark ages of Neovim LSP. Manually wiring up on_attach callbacks, juggling capabilities tables, writing 40 lines of boilerplate per server... You'll appreciate how far we've come.
Starting in 0.11, configuring LSP got dramatically simpler. You drop a file in your lsp/ directory, call vim.lsp.enable() with a list of servers, and you're done. My entire LSP configuration is basically:
vim.lsp.enable({
"bashls", "clangd", "cssls", "html",
"htmx","intelephense", "lua_ls",
"ruff", "rust_analyzer",
"sqls", "ts_ls"
})
That's it. Each server has its own config file under lsp/ with whatever specific settings it needs, but the core setup is just that one call. No mason. No lspconfig. No third-party plugin wrapping a third-party plugin. However, you still need to configure them.
0.12 pushes this further. There's a new :lsp command for managing clients interactively, semantic tokens got range requests so it only processes what's visible in your viewport (performance win), and code lens got reimplemented as virtual lines instead of virtual text. Inline completion support landed too. textDocument/inlineCompletion is a real thing now. The diagnostic system also picked up workspace diagnostics and related information display in floats.
Stimpack: My Plugin Loader
So here's the thing. Neovim 0.12 ships with vim.pack. It is a built-in package management API. And instead of using it directly like a normal person, I wrote a wrapper around it called Stimpack. Because of course I did. If you've read my post about rewriting PHP frameworks six times, you know I have a problem.
Stimpack is a lightweight Lua plugin loader that sits on top of vim.pack and gives me lazy loading, dependency resolution, build hooks, and startup profiling. Think of it as lazy.nvim's weird minimalist cousin.
Here's what a plugin spec looks like:
return {
"whleucka/mantis.nvim",
cmd = {
"MantisIssues",
"MantisSelectHost"
},
keys = {
{ "<leader>M", ":MantisIssues<cr>", desc = "Mantis Issues" },
},
dependencies = {
"nvim-lua/plenary.nvim",
"grapp-dev/nui-components.nvim",
"MunifTanjim/nui.nvim"
},
opts = require("config.mantis")
}
Each plugin gets its own file under lua/plugins/. Stimpack scans those files, resolves dependencies, and handles loading. Eagerly at startup or lazily on events, commands, filetypes, or keymaps. It tracks load times for every plugin so I can run :StimProfile and see exactly what's slowing me down.
Is this necessary? No. Does lazy.nvim do all this and more? Yes. Do I care? Also no. Building your own tools teaches you things that using someone else's tools never will. And the startup time is fast. I timed it. Don't ask me to prove it.
💉 Stimpack configured (26 plugins) in 10.63ms
🔌 Plugins loaded in 8.94ms
âš¡ UI Ready Time: 27.23ms
0.12 Features That Made Me Audibly React
There is a lot in this release. Here are the ones that actually changed how I use the editor:
vim.net.request()
Neovim can make HTTP requests natively now. No more shelling out to curl in your plugin code. This is going to be huge for plugin authors.
:restart
You can restart Neovim and it reattaches the UI. No more quitting and reopening. Just :restart. I don't know why this makes me so happy but it does.
:iput
Indent-aware put. If you've ever pasted code and then spent 30 seconds fixing the indentation, this is for you. I've already added it to muscle memory.
Inline diff improvementsdiffopt now supports inline:char and inline:word modes. Adjacent diff blocks get merged automatically. It's like someone actually looked at how people use diffs and made it not terrible.
i_CTRL-R is 10x fasterRegister insertion in insert mode got rewritten to insert literally instead of simulating keystrokes. 10x speedup. This is the kind of boring performance work that makes an editor feel snappy and nobody ever thanks the person who did it.
Treesitter node selectionv_an, v_in, v_]n, v_[n give you incremental treesitter-based selection. Select a node, expand to parent, shrink back. No plugin needed. This used to require nvim-treesitter-textobjects and now it's just... built in.
:wall ++pAuto-creates parent directories when saving. I cannot tell you how many times I've created a file in a new directory, hit :w, gotten an error, gone and mkdir'd, and then saved again. This is a quality of life improvement that borders on emotional.
The new default statuslineIt actually shows useful information now. Diagnostic counts, LSP progress, terminal exit codes. You can still override it, but the default is finally not embarrassing.
autocomplete optionBuilt-in auto-completion that triggers as you type. The completion system got function-based sources and limit specifications. pumborder gives you borders on the popup menu. Between this and blink.cmp, completion in Neovim is genuinely excellent now.
vim.glob.to_lpeg()50% faster globbing with proper LSP 3.17 spec support. Nobody's going to tweet about this but your LSP is going to feel it.
Smartcase in completionsmartcase now applies to completion filtering. Small change, massive improvement.
You can find all the new features on Neovim's website.
The Stuff I'm Running
Quick rundown of the plugins in my config:
- tokyonight.nvim for the colorscheme, because I have mass-market taste and I'm fine with it
- blink.cmp for completion, which is absurdly fast
- flash.nvim for motion. I can't go back to regular search
- mini.files and mini.pick for file management and fuzzy finding (thanks to Evgeni Chasnovkski)
- gitsigns.nvim and neogit for git
- lualine.nvim for the statusline
- which-key.nvim so I can actually remember my own keybindings
- LuaSnip + friendly-snippets for snippets
- toggleterm.nvim for a floating terminal
- smart-splits.nvim for window management
- nvim-treesitter because syntax highlighting without it is medieval
29 plugins total. Not minimal, not bloated.
Shoutouts
None of this happens without the people who build Neovim. I want to give a genuine shoutout to a few of the core team members whose work makes all of this possible:
Justin Keyes (https://github.com/justinmk) The lead maintainer. The person steering this ship. If you've ever looked at Neovim's vision document and thought "wow, someone actually has a plan," that's Justin. The work he's done to keep Neovim focused and ambitious while maintaining stability is something I don't think gets enough credit.
Maria Solano (https://github.com/MariaSolOs) Core maintainer and a driving force behind a lot of the LSP and completion improvements. The native LSP experience in 0.11 and 0.12 owes a lot to her work. If you're enjoying vim.lsp.enable() as much as I am, send her a thank you.
Gregory Anders (https://github.com/gpanders) Core maintainer who's been behind a ton of the quality-of-life improvements and API work. The kind of contributor who makes everything around them better.
bfredl (https://github.com/bfredl)Core maintainer and the person behind a lot of the rendering, grid, and performance work. The reason your Neovim feels fast? A lot of that is bfredl. The decorations API, the multigrid architecture, the performance improvements. Very nice.
These people are building one of the most important developer tools in the world, largely in their own time. If you use Neovim, consider sponsoring them on GitHub. Or at the very least, file good bug reports.
If you made it this far, thanks for reading. Go update to 0.12 and break something. This is the way 👹
Leave a Comment