rainbow-delimiters.nvim colours nested brackets with Tree-sitter queries
Rainbow delimiters for Neovim with Tree-sitter
At a glance
- What is it?
- The rainbow-delimiters.nvim plugin gives Neovim alternating colours for nested delimiters, using Tree-sitter to find the pairs, and it is built around the idea that the query and the strategy are configuration rather than code. It started as a fork of nvim-ts-rainbow2, which was a module for nvim-treesitter, and it exists as a standalone plugin because nvim-treesitter deprecated the module system.
- Who is it for?
- Adopt rainbow-delimiters.nvim if you read deeply nested code in Neovim and want the bracket levels told apart at a glance, and if you are willing to install a Tree-sitter parser for each language you want it to work in.
- 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 last received commits 19 days ago.
- What is it written in?
- Mainly Lua, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A fork that exists because nvim-treesitter dropped modules
The origin of this plugin is a deprecation, and the README explains it in two sentences.
Rainbow delimiters for Neovim provides alternating syntax highlighting, the rainbow parentheses effect, powered by Tree-sitter. It is a fork of nvim-ts-rainbow2, which had been implemented as a module for nvim-treesitter. Since nvim-treesitter deprecated the module system, the author had to create this standalone plugin.
That history explains several otherwise odd details. The plugin is on its own repository rather than inside nvim-treesitter, and it has a migration section specifically for people coming from nvim-ts-rainbow2, because the settings move and the names change. The original nvim-ts-rainbow project is credited in the attribution section with a link to its sourcehut page, and a list of contributors from the original author is thanked.
The stated goal is worth quoting in substance, because it explains the design. The goal is to have a hackable plugin which allows for different configuration of queries and strategies, both globally and per file type, and users can override and extend the built-in defaults through their own configuration.
Hackable is the operative word. A plugin that just colours brackets is a solved problem. A plugin where the bracket detection is a Tree-sitter query you can replace, and where the colouring strategy is a module you can swap, is a platform for a feature that is still being designed. The rest of the README is essentially an explanation of what you can change.
Tree-sitter queries are the configuration surface
The mechanism has two moving parts, and the README names both in the configuration example.
The first is the query, which is the Tree-sitter query that finds the delimiters to highlight. The default query is called rainbow-delimiters, and it can be overridden per file type. The repository has a queries/ directory at the root, which is where those queries live, and a language specific example in the configuration points Lua at a query named rainbow-blocks instead of the default.
The second is the strategy, which decides how the colours are assigned. The defaults are rainbow-delimiters.strategy.global and rainbow-delimiters.strategy.local, and the configuration maps the global strategy to the empty key and the local one to the vim file type.
The naming change from the original plugin is explained in the migration section and it is a good example of a small design decision carrying a lot of meaning. The default query is now called rainbow-delimiters rather than rainbow-parens, and the README gives the reason: for some languages like HTML the notion of parentheses does not make any sense, because in HTML the only meaningful delimiter is the tag. Hence the generic notion of a delimiter.
That is the difference between a plugin that works for curly brace languages and one that works for markup, and it also explains why the query is a configuration key rather than a constant. If a language has a delimiter concept that Tree-sitter can express as a query, you can point the plugin at it.
The practical requirement that comes with all this is stated in the installation section: you will need a Tree-sitter parser for each language you want to use rainbow delimiters with. The plugin does not ship parsers, and the author asks for help in the help wanted section, since there are only so many languages the author understands well enough to write queries for.
Configuration is a dictionary keyed by file type
The plugin works with no configuration at all, because it ships reasonable defaults that you can override. Configuration is done by setting entries in the Vim script dictionary g:rainbow_delimiters, and the example shows the full shape of it.
In Lua, the same dictionary is written as vim.g.rainbow_delimiters, and the strategy, query and priority tables are keyed first by the empty string, which is the default, and then by a file type:
strategy = {
[''] = 'rainbow-delimiters.strategy.global',
vim = 'rainbow-delimiters.strategy.local',
},
query = {
[''] = 'rainbow-delimiters',
lua = 'rainbow-blocks',
},
priority = {
[''] = 110,
lua = 210,
},Three separate tables is the important structural decision here. The query decides what counts as a delimiter, the strategy decides how levels are coloured, and the priority decides when the plugin's highlights win against whatever else is highlighting the same text. They are separated because they change for different reasons, and a language that needs a different query probably does not need a different strategy.
The highlight list is a plain array of highlight group names:
'RainbowDelimiterRed',
'RainbowDelimiterYellow',
'RainbowDelimiterBlue',
'RainbowDelimiterOrange',
'RainbowDelimiterGreen',
'RainbowDelimiterViolet',
'RainbowDelimiterCyan',
},
}Seven groups, and the naming matters because these are the groups a user colours in their own colourscheme. The migration section notes that the prefix is RainbowDelimiter instead of the old TSRainbow, so a custom colourscheme carried over from nvim-ts-rainbow2 needs its group names updated.
For people who prefer a setup call, the module rainbow-delimiters.setup accepts the same parameters as g:rainbow_delimiters:
require('rainbow-delimiters.setup').setup {
strategy = {
-- ...
},
query = {
-- ...
},
highlight = {
-- ...
},
}The manual at doc/rainbow-delimiters.txt is where the README sends you for the details.
The submodule symlink exists to keep package managers out
The contributing section contains the most unusual piece of engineering in the repository, and the reason for it is worth understanding if you intend to work on the plugin.
The short version of the instructions is three commands:
ln -s .submodules .gitmodules
git submodule init
git submodule updated --checkoutThe explanation follows. There are dependencies needed to run the tests, and these are included as Git submodules. The problem is that a number of package managers will download submodules by default, which means users end up with a bunch of stuff installed that they do not want. There is no way to tell Git to use a different file, so a symbolic link has to be created instead if the submodules are actually wanted.
So the repository keeps its real submodule definitions in a file named .submodules, and the link makes .gitmodules point at it for the people who are testing. The installation section makes the user facing half of this explicit: install it like any other Neovim plugin, you do not need the Git submodules of this repository, they are just used for development and will not cause any harm, they will just bloat your setup.
That is a thoughtful solution to a problem that every plugin with test-only dependencies has, and it is the kind of detail that tells you the author has thought about the plugin manager ecosystem rather than only about the plugin.
The rest of the repository is consistent with that. There is a .busted file for the test runner, a test/ directory, a makefile, a .nvimrc for development, a .luals/ directory and a .luarc.json for the Lua language server configuration, an .editorconfig, and a CHANGELOG.rst, a CONTRIBUTING.rst and a HACKING.rst.
Neovim support is a sliding window, not a range
The compatibility policy is short and unusually precise, and it is the section to read before pinning a version.
The reason for it is stated: Tree-sitter support in Neovim is still experimental. As long as that remains the case, the Neovim version compatibility will be a sliding window encompassing the currently released version, the upcoming version and the previously released version, in that order of priority. If any of those conflict with each other, the higher priority version is preferred. The README says this should cover the needs of most Neovim users, and that the plugin may still be compatible with even older releases if convenient, but that is not a guarantee.
Two consequences follow. First, there is no minimum version you can rely on from the documentation alone, because the window moves with Neovim's own release cadence, which means a plugin manager that pins Neovim to an old version may find this plugin stopping to work. Second, the policy is explicitly conditional on Neovim's own experimental status, so the day Tree-sitter support stops being experimental, the sliding window can be replaced with a fixed range.
The stability claim is bounded in the same way. The plugin and its API should be considered stable insofar as breaking changes will only happen if changes to Neovim necessitate them, and intentionally breaking backwards compatibility necessitates a new release of the plugin.
The homepage is on GitLab at gitlab.com/HiPhish/rainbow-delimiters.nvim, the default branch is master, the licence is Apache-2.0 with the text in the LICENSE file, and the repository has no GitHub releases. The last push was on 2026-10-05.
Migrating from nvim-ts-rainbow2 is five small edits
The migration section is short and practical, and it is worth reproducing here because anyone arriving from the predecessor will hit these differences.
Settings are stored in the global variable g:rainbow-delimiters, which has the same keys as the old settings, so that is where the settings live now. The default strategy and query have index the empty string instead of 1, which is the same indexing convention used throughout the configuration, where the empty string is the default and a file type overrides it.
The default highlight groups have the prefix RainbowDelimiter instead of TSRainbow, for example RainbowDelimiterRed instead of TSRainbowRed. The default query is now called rainbow-delimiters instead of rainbow-parens, for the reason given earlier, that the notion of parentheses does not apply to languages like HTML where the tag is the delimiter. And the public Lua module is called rainbow-delimiters instead of ts-rainbow.
The README describes the conversion as straight-forward, and it is: no new concepts, just different names and one changed index.
The one structural point to keep in mind is the location of the settings. The biggest change is where the settings are stored, and for a user of the old plugin who had a large configuration, that is the part to spend time on, because everything else is a rename that a search and replace will handle.
The plugin asks for queries, and documents itself in Vim help
Two things in the README point at how the project is meant to be extended, and both are about work rather than code.
The first is the help wanted section. The author says there are only so many languages which the author understands to the point that queries can be written for them, and asks people who want support for a new language to contribute code, pointing to the CONTRIBUTING document for the details. The manual at doc/rainbow-delimiters.txt is where the plugin's own documentation lives, referenced as the manual from the README.
That combination, a query based design plus an explicit invitation to write queries for languages, is the extension path. Supporting a language that the author does not know means writing a Tree-sitter query for it, adding it to the queries/ directory, and pointing the query table at it, and the priority and strategy tables are already per file type so nothing else has to change.
The repository listing shows the supporting structure that makes this possible. There is a queries/ directory, a lua/ directory for the plugin code, an autoload/ directory, a plugin/ directory, a doc/ directory for the help file, a LICENSES/ directory for the licence texts, and a .gitlab/ directory for the GitLab specific configuration, with the GitHub side in .github/.
The final note for anyone deciding whether to use it is about the trade-off the plugin makes. A query per language and a Tree-sitter parser per language are both prerequisites, and the plugin ships neither. What it ships is a small, hackable mechanism that turns those queries into alternating colours, with the strategy and the priority under your control.
Editorial conclusion
Adopt rainbow-delimiters.nvim if you read deeply nested code in Neovim and want the bracket levels told apart at a glance, and if you are willing to install a Tree-sitter parser for each language you want it to work in. Do not adopt it if you want the feature to be zero configuration on a machine with no Tree-sitter setup, because parsers are a prerequisite, and do not adopt it without reading the version compatibility policy, because the supported Neovim versions are a sliding window rather than a range. Before you configure anything, decide whether you want the global or the local strategy, because the default is the global one and switching to a per file type strategy changes which files are affected, and check the manual in doc/rainbow-delimiters.txt for the details the README points there for.
Frequently asked questions
What does rainbow-delimiters.nvim do in Neovim?
It provides alternating syntax highlighting for nested delimiters, the rainbow parentheses effect, powered by Tree-sitter. The queries and the strategy are configurable globally and per file type, and the built-in defaults can be overridden or extended.
Do I need Tree-sitter parsers for rainbow-delimiters.nvim?
Yes. The README says you will need a Tree-sitter parser for each language you want to use rainbow delimiters with. The plugin ships queries, not parsers, and the author asks for help writing queries for new languages.
How do I configure the rainbow delimiter highlight colours?
Set the highlight array in g:rainbow_delimiters or in the rainbow-delimiters.setup module, listing the highlight group names such as RainbowDelimiterRed and RainbowDelimiterYellow. You then colour those groups in your own colourscheme.
What changed when moving from nvim-ts-rainbow2 to rainbow-delimiters.nvim?
Settings now live in g:rainbow-delimiters, the default index is the empty string instead of 1, the highlight groups use the RainbowDelimiter prefix instead of TSRainbow, the default query is called rainbow-delimiters instead of rainbow-parens, and the Lua module is rainbow-delimiters instead of ts-rainbow.
Which Neovim versions does rainbow-delimiters.nvim support?
The compatibility is a sliding window of the currently released version, the upcoming version and the previously released version, in that order of priority, as long as Tree-sitter support in Neovim remains experimental. Intentionally breaking backwards compatibility requires a new plugin release.
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/hiphish-rainbow-delimiters-nvim)Was this useful?