Tree-sitter migration guide for Neovim 0.12
April 2, 2026
Neovim recently updated to 0.12 with major improvements to the built-in LSP client and better terminal handling among other nice things.
This update broke my setup: opening Neovim afterwards showed a wall of attempt to call method 'start' (a nil value) error from nvim-treesitter along with a full stack trace.
This guide summarizes what I did to get it all working again.
What is treesitter?
Treesitter helps Neovim and other IDEs like VSCode understand the structure of the code. This is then used to power many code editor features like highlighting, indentation, and code folding.
To nerd out a bit, treesitter works by building a concrete syntax tree (CST) of the source code under the hood. This CST is roughly similar to the DOM tree for HTML, both being structured representations of the underlying text.
The tree-sitter docs has a cool playground that lets you see the syntax tree for a piece of code in real time.
What to change in nvim-treesitter
Neovim bundles the treesitter runtime, but most people use the nvim-treesitter plugin to manage parser installation and configuration.
That plugin got a full rewrite on a new main branch. The old master branch is frozen and won't work with Neovim 0.12.
1. Install the tree-sitter CLI
The new nvim-treesitter compiles parsers locally and depends on the tree-sitter CLI. The old version bundled everything. The new one doesn't so we have to install it manually.
2. Reinstall the plugin
These code examples reflect my lazy.nvim plugin manager. Adjust for your plugin manager if you use something else.
The default branch changed from master to main. Update your plugin spec to pull from the new branch:
{
'nvim-treesitter/nvim-treesitter',
branch = 'master',
branch = 'main', -- optional as main is default, but I like being explicit
...
},Find nvim-treesitter in the lazy.nvim UI, press x to remove the old version, then :Lazy update nvim-treesitter to pull the new main branch.
3. Fix the module name
The old config module nvim-treesitter.configs no longer exists. The new plugin exports setup() from the top-level nvim-treesitter module. If you have a main field in your lazy.nvim spec, update it:
main = 'nvim-treesitter.configs',
main = 'nvim-treesitter', 4. Enable highlighting and indentation yourself
The old plugin had a module system where you'd enable highlighting and indentation by passing options to setup().
The new plugin simplifies the API and just handles parser installation, so we need to enable these features ourselves via a FileType autocmd:
opts = {
highlight = { enable = true },
indent = { enable = true },
-- ...
},
init = function()
vim.api.nvim_create_autocmd('FileType', {
callback = function()
-- Enable treesitter highlighting and disable regex syntax
pcall(vim.treesitter.start)
-- Enable treesitter-based indentation
vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"
end,
})
-- ...
end,5. Replace ensure_installed
ensure_installed is no longer a config option. You call the install API yourself instead.
Here's an init callback that diffs against already-installed parsers so it doesn't reinstall everything on every startup:
init = function()
local ensureInstalled = {
'lua', 'python', 'typescript',
-- ... your parsers
}
local alreadyInstalled = require('nvim-treesitter.config').get_installed()
local parsersToInstall = vim.iter(ensureInstalled)
:filter(function(parser)
return not vim.tbl_contains(alreadyInstalled, parser)
end)
:totable()
require('nvim-treesitter').install(parsersToInstall)
end,Textobjects (optional)
If you use nvim-treesitter-textobjects, same story. You need its main branch too:
{
'nvim-treesitter/nvim-treesitter-textobjects',
branch = 'master',
branch = 'main',
...
}Last steps
:Lazy update nvim-treesitterto pull the newmainbranch:TSUninstall allto remove old parsers compiled by themasterbranch- Restart Neovim
:TSUpdateto rebuild parsers with the new compiler:checkhealth nvim-treesitterto make sure everything's wired up