Inside nvim-treesitter: an incompatible rewrite, pinned parsers, and five query features
Nvim Treesitter configurations and abstraction layer
At a glance
- What is it?
- nvim-treesitter is now a parser installer plus a set of queries, split for Neovim 0.12, where the plugin itself no longer owns highlighting or folds. The consequences show up in what you must remember to update and what the feature list no longer covers.
- Who is it for?
- nvim-treesitter is worth setting up if you are on Neovim 0.12 or a nightly and you accept owning parser versions yourself, because the query collection is the part that still has to live somewhere and this is where it lives. It is not worth it if you want text object queries, which are absent from its feature list, or if your setup lazy-loads plugins, which it states it does not support.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Tree-sitter Query, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- nvim-treesitter/nvim-treesitter14,534 ★ · +127
| Repository | 2026-09-22 | 2026-11-14 |
|---|---|---|
| nvim-treesitter/nvim-treesitter | 14.4k | 14.5k |
127 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The rewrite is incompatible, and the old branch is frozen not gone
The first thing the README does is warn, in a caution block, that this is a full, incompatible rewrite, and that you should treat it as a different plugin to set up from scratch. There is no migration path in the instructions because the project does not offer one. What it offers instead is a branch: the master branch is locked but remains available for backward compatibility with Nvim 0.11. So a reader has two coherent configurations, this plugin on Neovim 0.12 or later, or the frozen master branch on 0.11, and mixing pieces of the two is the state the warning exists to prevent. The practical consequence is that adopting the current branch means rebuilding your configuration rather than editing it, and staying put means accepting a branch that no longer receives fixes.
Parsers are version-pinned, so the update step cannot be optional
The plugin is only guaranteed to work with specific versions of language parsers, and those versions are pinned in a parser.lua table. That single sentence drives most of the operational advice. When the plugin is upgraded, every installed parser has to be brought to the version the new plugin expects, using the update command, and the project calls automating this strongly recommended, offering a plugin manager spec as the example:
{
'nvim-treesitter/nvim-treesitter',
lazy = false,
build = ':TSUpdate'
}Note the two settings working together. The build hook runs the update command after every plugin update, and lazy is explicitly false, because a separate notice says the plugin does not support lazy-loading at all. So a configuration that defers loading until a file opens is in direct conflict with a requirement of the plugin, and a user who skips the build step keeps parsers at versions the new code was not written against.
Highlighting and folds belong to Neovim, indentation belongs to the plugin
The feature list is short and each entry names who provides it. Treesitter highlighting is provided by Neovim, not by this plugin, and enabling it for a filetype means calling vim.treesitter.start() from an ftplugin for that filetype or from a FileType autocommand. Folds are also provided by Neovim, enabled by two window options:
vim.wo[0][0].foldexpr = 'v:lua.vim.treesitter.foldexpr()'
vim.wo[0][0].foldmethod = 'expr'Indentation is the exception. That one is provided by the plugin and is labeled experimental, so enabling it means accepting a feature the project itself flags as unfinished:
vim.bo.indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()"The quotes in that line are noted as specific, which tells you the form is not interchangeable with the versions above. Injections for multi-language documents need no setup. The last entry, locals queries for looking up definitions and references in a scope, is not used by the plugin at all and is kept for limited backward compatibility, so a fresh install is carrying queries nothing reads.
install() returns before it finishes, so bootstrapping needs wait()
Parser installation is expressed as a Lua call:
require('nvim-treesitter').install({ 'rust', 'javascript', 'zig' }):wait(300000) -- wait max. 5 minutesCalling it on parsers that are already installed is a no-op, which makes it safe to leave in a configuration. What is not safe is assuming the call has finished when it returns, because the function runs asynchronously. In a script context such as bootstrapping, where the next step depends on the parser being present, you have to wait on it explicitly, and the example shows a ceiling of five minutes. A configuration that installs parsers at startup without that wait is racing its own first buffer.
install_dir is prepended to runtimepath so your parsers win
Configuration is optional. The plugin works on defaults without any call to setup, and the only option shown sets where parsers and queries are installed:
require('nvim-treesitter').setup {
-- Directory to install parsers and queries to (prepended to `runtimepath` to have priority)
install_dir = vim.fn.stdpath('data') .. '/site'
}The parenthetical is the whole mechanism. The directory is prepended to the runtimepath so it has priority, which means a parser sitting there is found before one that arrived another way, such as a system installation or a copy shipped by a distribution package. That is a useful escape hatch when two tools disagree about a parser version, and it is also a way to end up debugging a parser you did not intend to use, because priority is decided by path order rather than by version. The default writes under your Neovim data directory.
A custom parser is hand-registered inside a TSUpdate autocommand
Adding a language the project does not list is a three step manual procedure, and the example uses a made-up zimbu parser. A User autocommand on the TSUpdate pattern assigns into the parsers module, giving an install_info table with a repository url and a revision, where revision is a commit hash and HEAD is used if it is missing, plus optional entries for branch when it differs from the default, location when the parser sits in a subdirectory of a monorepo, and generate when the repository has no pre-generated src/parser.c. A local checkout takes a different route, using a path key with the same optional entries, and that form always uses the state of the directory as-is, with branch and revision ignored. If the parser name differs from the filetype Neovim uses, it has to be registered by hand with vim.treesitter.language.register, and then you start Neovim and install it with the install command. One hard constraint closes the section: an external scanner has to be written in C.
The Makefile downloads its own Neovim, formatter and query language server
Testing is driven by a Makefile that fetches four tools into a local dependency directory rather than using what is installed. The versions are variables at the top: the Neovim build defaults to nightly, and the EmmyLua language analyzer is pinned at 0.25.1, while the downloader is a curl invocation with directory creation. The architecture table branches on the operating system, mapping macOS to the arm64 Neovim, the darwin-arm64 language analyzer, the macos-aarch64 StyLua build and the aarch64 Rust target, and everything else to the x86_64 equivalents. The fourth tool is ts_query_ls from ribru17's releases, which is a language server for tree-sitter query files and matches the .tsqueryrc.json sitting at the repository root. The consequence for a contributor is that a test run reaches out to GitHub release URLs for binaries, and two of those targets resolve latest rather than a fixed version, so a broken run can come from upstream rather than from a local change.
Only stable and nightly are supported, and the plugin has no releases
The support policy is stated as exactly two targets, the latest stable Neovim release and the latest nightly prerelease, with the explicit note that other versions may work but are neither tested nor considered for fixes. Everything else in the project follows from that choice. The rewrite targets Neovim 0.12.0 or later on nightly, the tree-sitter command line tool has to be 0.26.1 or later and must come from a package manager rather than npm, and a C compiler is required because parsers are compiled. Meanwhile the repository itself publishes no GitHub releases, so there is no tag to pin for the plugin. The main branch was pushed on 2 November 2026 and the project is not archived, but the practical position is that you track the branch while the plugin pins the parsers, which is the opposite arrangement from the usual one.
Editorial conclusion
nvim-treesitter is worth setting up if you are on Neovim 0.12 or a nightly and you accept owning parser versions yourself, because the query collection is the part that still has to live somewhere and this is where it lives. It is not worth it if you want text object queries, which are absent from its feature list, or if your setup lazy-loads plugins, which it states it does not support. Before you switch, read the rewrite notice and plan a fresh configuration rather than a migration, decide whether the experimental indentation is something you want in your ftplugin, and set your build step to run the update command so no parser is left behind on an old version.
Frequently asked questions
how to install nvim-treesitter
Install it with your package manager, or with the native package feature of vim. It requires Neovim 0.12.0 or later on nightly, tar and curl in your path, tree-sitter-cli 0.26.1 or later installed through a package manager rather than npm, and a C compiler.
what is nvim treesitter used for
Three things: functions for installing, updating and removing tree-sitter parsers, a collection of queries that enable the tree-sitter features built into Neovim for those languages, and a staging ground for tree-sitter based features being considered for upstreaming into Neovim.
How to setup treesitter in nvim?
The features are not automatically enabled. Highlighting needs vim.treesitter.start() in an ftplugin or a FileType autocommand, folds need foldexpr set to the tree-sitter expression with foldmethod set to expr, and indentation needs an indentexpr pointing at the plugin's indentexpr function.
What is a good alternative to nvim-treesitter?
For a setup on Nvim 0.11, the alternative the project names is its own master branch, which is locked but remains available for backward compatibility. For the current line, the plugin itself is the collection of queries, and it points at Neovim's own built-in features for highlighting and folding.
how to use nvim treesitter textobjects
The supported feature list covers highlighting, folds, indentation, injections and locals, and text objects are not among them. Supporting a feature for a language needs both a parser and a language specific query file for that feature, which is why the supported languages page and the query set have to line up.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nvim-treesitter-nvim-treesitter)Star history chart for your README
[](https://hysenlabs.com/projects/nvim-treesitter-nvim-treesitter)Was this useful?