nvim-origami and folding in Neovim driven by the LSP
Fold with relentless elegance. A collection of quality-of-life features related to folding.
At a glance
- What is it?
- nvim-origami is a Neovim plugin that takes its fold ranges from the language server rather than from syntax trees, decorates the closed fold with a line count, diagnostics and git change markers, and overloads h, l, ^ and $ so that folding and unfolding replace the z-prefix keymaps. The interesting engineering is the three-level fallback, LSP then Treesitter then indent, and the interesting constraint is that it is incompatible with nvim-ufo.
- Who is it for?
- nvim-origami is a good fit for a Neovim user with a language server configured who finds the z-prefix fold commands slow or clumsy, because the fold ranges come from the same source as the language server's own folding, and the h, l, ^ and $ overloads put folding on the same keys as movement.
- Can I use it commercially?
- Yes. MIT 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 81 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Folding from the language server
nvim-origami is a collection of quality-of-life features related to folding, and the first of them is where the folds come from. It uses the LSP to provide folds, with Treesitter as a fallback if the LSP does not provide folding information, and indent-based folding if neither is available.
That ordering is the design decision worth understanding. A language server knows the semantic structure of a file, so its folding ranges follow real blocks rather than the indentation heuristics a syntax parser infers. The cost is that you need a language server running, and the fallback chain exists so the plugin degrades rather than breaks.
The auto-fold feature depends on the same thing. It automatically folds comments and/or imports when opening a file, and the readme is explicit that this requires that the folding information is provided by an LSP. That is a sharper constraint than it first appears, because with a Treesitter-only setup you get manual folding but not the automatic part.
The project positions itself against nvim-ufo, stating that nvim-origami replaces most features of nvim-ufo in a much more lightweight manner and adds some features of its own. The requirements section says the same thing more bluntly: you must not be using nvim-ufo, since nvim-origami is incompatible with it.
The primary language is Lua, the licence is MIT, the default branch is main, and the last push was on 2026-08-03. There are no GitHub releases, so the plugin is installed from the repository rather than from a tagged version.
The audience is a Neovim user who has a language server set up, which by now is most people using Neovim with a modern configuration, and who wants the folding commands to live where their fingers already are.
The h, l, ^ and $ overloads
The feature that most distinguishes this plugin is the remapping of four ordinary motion keys to also fold and unfold.
The h key folds a line when used on the first non-blank character or before, and behaves as regular h otherwise. The l key unfolds the cursorline when used on a folded line and behaves as regular l otherwise. The ^ and $ keys work the same way as h and l except that they fold and unfold recursively.
The point of the design is stated in the readme: it allows you to ditch zc, zo, za, zC and zO, since you only need h, l, ^ and $. Five z-prefix commands become four keys you already have in muscle memory, and the conditional behaviour means the keys keep their original function everywhere the fold action does not apply.
The conditional logic is what makes this safe rather than annoying. h is only intercepted in the position where folding makes sense, and l only on a folded line. Everywhere else they are the keys you expect.
If you have remapped horizontal movement to something else, the readme tells you to turn the feature off and map it yourself, and gives the four lines to copy:
vim.keymap.set("n", "<Left>", function() require("origami").h() end)
vim.keymap.set("n", "<Right>", function() require("origami").l() end)
vim.keymap.set("n", "<Home>", function() require("origami").caret() end)
vim.keymap.set("n", "<End>", function() require("origami").dollar() end)The plugin exposes its own h, l, caret and dollar functions, so a custom mapping calls into the same behaviour rather than reimplementing it.
The configuration block for this is small and each option addresses a specific annoyance. setup controls whether the keys are modified at all. closeOnlyOnFirstColumn, false by default, makes h and ^ only fold in the first column. And scrollLeftOnCaret, also false by default, decides whether ^ should scroll left, which the readme describes as basically mapped to 0^.
Foldtext decorations: counts, diagnostics and git changes
The second headline feature is fold-text decorations, which display the number of lines, diagnostics and git changes in the fold while preserving syntax highlighting.
The syntax highlighting part is the harder half and the reason this is a plugin rather than a foldtext option. The typical foldtext recipe replaces the whole folded line with a single string, which throws away the highlighting of the text you were reading. Here the decoration is added alongside the existing content.
The implementation was suggested by u/marjrohn in a Reddit thread about adding decoration to folded lines, and the credits section credits that person for the decorator approach to styling foldtext.
The counts come from different sources. Diagnostics come from the language server's own diagnostics, and the configuration notes that it uses hlgroups and icons from vim.diagnostic.config().signs, which means the diagnostic markers in a fold look like the ones elsewhere in your buffer. Git change counts require gitsigns.nvim or mini.diff, and the readme says so explicitly.
The padding block controls the space around the decoration, with a character, a width that can be a function of the current virtual text length, and an optional highlight group. The lineCount block has a template of "%d lines", where %d is replaced with the number of folded lines, and a highlight group of Comment by default. The diagnosticsCount and gitsignsCount options are booleans that turn those two counts on.
There is also a disableOnFt option, a list of filetypes where the decorations are suppressed, and the default value in the sample configuration is snacks_picker_input, which is a picker input where a decorated fold would be in the way.
Installation and the required setup call
The requirements are short: nvim 0.11 or newer, and not using nvim-ufo.
The plugin manager example shows the shape of the configuration, and one detail in it is easy to miss:
-- lazy.nvim
{
"chrisgrieser/nvim-origami",
event = "VeryLazy",
opts = {}, -- required even when using default config
-- recommended: disable vim's auto-folding
init = function()
vim.opt.foldlevel = 99
vim.opt.foldlevelstart = 99
end,
}The opts table is marked as required even when using the default config, and the configuration section states plainly that the.setup call is required. That is a real constraint rather than a stylistic one: a plugin that registers keymaps and computes fold ranges needs its options resolved before it runs, and a plugin manager that lazy-loads it will not call setup for you unless the options key is present.
The init block is the recommended part, and the comment says why: it disables Neovim's own auto-folding by setting foldlevel and foldlevelstart to 99. Without that, Neovim's built-in folding and the plugin's folding disagree about what is folded, which produces the visible symptom of folds opening unexpectedly.
The VeryLazy event means the plugin loads after startup rather than on first file open, which suits a plugin whose work is keymap registration rather than buffer setup.
The full default configuration covers the LSP fallback behaviour, the search pause, the foldtext decorations, the auto-fold kinds and the fold keymap options, and while every individual option has a default, the setup call itself must still be made.
Search pausing and the known issues
The remaining features are smaller but solve real friction. Pause folds while searching restores them when the search is done, since normally folds are opened when you search for text inside them and stay open afterwards, which is disorienting when you then search again elsewhere.
All features are independent of each other, so you can freely choose to only enable the ones you want.
The FAQ section is unusually candid about what does not work, and that is worth reading before you install.
There is an error when opening a file:
Error executing vim.schedule lua callback:
...0.11.2/share/nvim/runtime/lua/vim/lsp/_folding_range.lua:311: attempt to index a nil valueThe readme says this error occasionally occurs with autoFold enabled, and that it is not caused by nvim-origami but by a bug with vim.lsp.foldclose() in nvim core, and that a future version of nvim will hopefully fix it. That is an honest attribution of a bug to the upstream editor rather than a workaround in the plugin.
There is also the problem of folds being opened after running a formatter, which the readme attributes to a known issue of many formatting plugins and not to nvim-origami, and it names the only two tools the author is aware of that can preserve folds, the efm-language-server and conform.nvim.
For debugging, there are two inspection calls that dump the folds the LSP provides:
require("origami").inspectLspFolds("special") -- comments & imports only
require("origami").inspectLspFolds("all")That is the first thing to run when a fold appears where you do not expect one, because it tells you whether the range came from the server or from the plugin's own logic.
The project also carries a .stylua.toml and a .rumdl.toml, so formatting and linting are configured in the repository, and the author is a sociologist whose day job is studying the governance of the app economy, which is the sort of background that explains the careful attention to Neovim core's own folding behaviour.
Editorial conclusion
nvim-origami is a good fit for a Neovim user with a language server configured who finds the z-prefix fold commands slow or clumsy, because the fold ranges come from the same source as the language server's own folding, and the h, l, ^ and $ overloads put folding on the same keys as movement. It is a poor fit if you use nvim-ufo, since the plugin states they are incompatible, and a poor fit if your language server does not provide folding information and you have no Treesitter parser, since the fallbacks are the only thing left. Before installing, read the autoFold section, because automatic comment and import folding requires that the folding information comes from an LSP, and set foldlevel and foldlevelstart to 99 as the readme recommends so Neovim's own auto-folding does not fight the plugin.
Frequently asked questions
Where does nvim-origami get its fold ranges from?
From the LSP first, with Treesitter as a fallback if the language server does not provide folding information, and indent-based folding if neither is available. The auto-fold feature for comments and imports requires the folding information to come from an LSP.
How does nvim-origami change the h, l, ^ and $ keys?
h folds a line when used on the first non-blank character or before and behaves as regular h otherwise, l unfolds the cursorline on a folded line and behaves as regular l otherwise, and ^ and $ work the same way but fold and unfold recursively, which lets you drop zc, zo, za, zC and zO.
What do the nvim-origami fold text decorations show?
The number of lines, diagnostics and git changes inside the fold, while preserving syntax highlighting. Diagnostics use the hlgroups and icons from vim.diagnostic.config().signs, and the git change count requires gitsigns.nvim or mini.diff.
Is nvim-origami compatible with nvim-ufo?
No. The readme states that you must not be using nvim-ufo, since nvim-origami is incompatible with it, and it positions itself as a lighter replacement for most nvim-ufo features.
What do I need to set up after installing nvim-origami?
The setup call is required even with default options, so pass an empty opts table to your plugin manager. It is also recommended to set vim.opt.foldlevel and vim.opt.foldlevelstart to 99 in the init phase so Neovim's own auto-folding does not conflict with the plugin.
How do I debug folding problems in nvim-origami?
Call require("origami").inspectLspFolds("special") for comments and imports only, or require("origami").inspectLspFolds("all") to see every fold range the language server reports, which tells you whether a range came from the server or from the plugin.
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/chrisgrieser-nvim-origami)Was this useful?