Open-source project
mrcjkb/haskell-tools.nvim avatar
mrcjkb/haskell-tools.nvim

haskell-tools.nvim: LSP, Hoogle and a GHCi REPL for Haskell in Neovim

🦥 Supercharge your Haskell experience in neovim!

615 stars23 forksLuaGPL-2.0

At a glance

What is it?
haskell-tools.nvim is a Lua plugin for Neovim that sets up the haskell-language-server client and adds the Haskell specific tooling around it, Hoogle signature lookup, a toggleable GHCi REPL, evaluation of code snippets and a Telescope extension, all lazy initialised with no setup call and no dependency on lspconfig. It suits a Haskell developer who wants more than the baseline language server, and the version requirement is explicit, Neovim 0.12 or newer, with older Neovim users pointed at previous major versions in the changelog.
Who is it for?
Adopt haskell-tools.nvim if you write Haskell in Neovim and want the language server plus Hoogle lookup, a REPL and snippet evaluation configured for you without wiring lspconfig by hand.
Can I use it commercially?
Yes, with conditions. GPL-2.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository received new commits within the last day.
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 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

No setup function, no lspconfig, lazy by design

haskell-tools.nvim is a Neovim plugin whose three headline properties are stated at the top of the README: it just works with no need to call `setup`, it has no dependency on `lspconfig`, and it uses lazy initialization by design.

Those three together determine how you install it. Because there is no setup call, there is nothing to configure before the plugin works, and because the plugin does not depend on lspconfig, you are not obliged to run the nvim-lspconfig configuration for haskell-language-server. There is a warning about exactly that, saying not to call the nvim-lspconfig.hls setup or set up the lsp client for haskell-language-server manually, as doing so may cause conflicts. The plugin configures the builtin LSP client itself.

The installation with Neovim's built-in plugin manager is:

lua
vim.pack.add {{
  src = 'https://github.com/mrcjkb/haskell-tools.nvim',
  -- To avoid being surprised by breaking changes,
  -- I recommend you set a version range
  version = vim.version.range('^10')
}}

The comment about setting a version range is worth taking seriously, and the tip section repeats it: it is suggested to pin to tagged releases if you would like to avoid breaking changes. The plugin has moved through major versions, with v10.0.0 on 2026-06-06, v10.0.1 on 2026-06-29 and v11.0.0 on 2026-09-20, so a major bump is a real event in this project and the pin is the difference between a smooth upgrade and a morning spent reading the changelog.

The plugin is also available on LuaRocks and can be installed with rocks.nvim:

sh
:Rocks install haskell-tools.nvim

and the lazy.nvim example sets `lazy = false` with the comment that this plugin implements proper lazy-loading, so there is no need for lazy.nvim to lazy-load it. That is a small but correct distinction, since the plugin's own lazy loading is at the level of the language server rather than the plugin file.

The required version is Neovim 0.12 or newer, and for versions compatible with older Neovim releases the README points at previous major version bumps in the changelog. NixOS users with flakes enabled get outputs in the form of a package and an overlay, and it is also available in nixpkgs.

What you get beyond the language server

The README has a section asking whether you need the plugin at all, and the answer is a good indication of what it adds. If you are starting out with Haskell, nvim-lspconfig.hls is probably enough. It provides the lowest common denominator of LSP support. This plugin is for those who would like additional features that are specific to Haskell tooling.

The optional dependencies tell you what those features are. haskell-language-server is recommended. telescope.nvim is optional. A local hoogle installation is recommended for better hoogle search performance. fast-tags is for automatic tag generation as a fallback for vim.lsp.tagfunc. And haskell-debugger with nvim-dap is listed as optional, which is the debugging path, since the topic tags include dap and debug-adapter-protocol.

The keymap suggestions in the README show the surface concretely, and they are the fastest way to see what the plugin adds over a plain LSP client:

lua
-- ~/.config/nvim/after/ftplugin/haskell.lua
local ht = require('haskell-tools')
local bufnr = vim.api.nvim_get_current_buf()
local opts = { noremap = true, silent = true, buffer = bufnr, }
-- haskell-language-server relies heavily on codeLenses,
-- so auto-refresh (see advanced configuration) is enabled by default
vim.keymap.set('n', '<space>cl', vim.lsp.codelens.run, opts)
-- Hoogle search for the type signature of the definition under the cursor
vim.keymap.set('n', '<space>hs', ht.hoogle.hoogle_signature, opts)
-- Evaluate all code snippets
vim.keymap.set('n', '<space>ea', ht.lsp.buf_eval_all, opts)
-- Toggle a GHCi repl for the current package
vim.keymap.set('n', '<leader>rr', ht.repl.toggle, opts)

Two things to note about how those keymaps are set up. First, they live in `~/.config/nvim/after/ftplugin/haskell.lua`, with a similar file for cabal, and the reason given is that most keymaps are only useful in haskell and/or cabal files. The base-directories help page is referenced, which is the Neovim mechanism for per-filetype files.

Second, and this is the part that bites, the same file must not set `vim.g.haskell_tools`, because the file is sourced after the plugin is initialized. That is marked as important. It is a small configuration detail with an awkward failure mode, since the natural instinct when writing a filetype plugin is to set the plugin's options there.

The functions themselves show the range. `ht.hoogle.hoogle_signature` does a Hoogle search for the type signature of the definition under the cursor, which is the Haskell-specific capability that plain LSP does not give you. `ht.lsp.buf_eval_all` evaluates all code snippets in the buffer, and `ht.repl.toggle` starts a GHCi REPL for the current package, with a separate variant for the current buffer, and `ht.repl.quit` to close it.

The plugin ships as Lua, docs, specs and Nix outputs

The repository layout shows a project that takes its packaging seriously.

There is `lua/` for the plugin code, `ftplugin/` for the filetype behaviour, `doc/` for the Vim help documentation, `spec/` for the test suite, `troubleshooting/` as a directory of its own, and `nix/` plus `flake.nix` and `flake.lock` for the Nix packaging. There is a `haskell-tools.nvim-dev-1.rockspec` at the root for the LuaRocks distribution, and a `lux.toml` with `lux.lock` for another package manager.

The tooling files are equally deliberate. There is a `.luacheckrc` for the linter, a `.luarc.json` for the Lua language server configuration, a `.stylua.toml` for the formatter, a `.neoconf.json`, a `.editorconfig`, a `.busted` directory for the test framework configuration, and a `.envrc` for direnv. `feedback.yaml` suggests a structured feedback mechanism, and there is a `CHANGELOG.md` that the README explicitly relies on for the older-Neovim instructions.

Two things follow from this. The documentation is generated rather than written by hand, since the README says that to manually generate documentation you use `:helptags ALL`, which is the standard step for a Neovim plugin that ships a `doc/` directory. And the project is packaged for more than one ecosystem, which is unusual and reflects an audience that arrives with a specific toolchain already chosen.

The troubleshooting directory is worth noting as a category. A plugin that wraps a language server, a documentation search tool, a tag generator and a REPL will have failure modes that span all four, and a directory of its own for that kind of content is a sign the maintainer expects them rather than discovering them one at a time.

The project is GPL-2.0 licensed, the primary language is Lua, and the last push was on 2026-10-20.

Why the plugin insists on owning the language server client

The warning against configuring the haskell-language-server client yourself is the most consequential line in the README, and it is worth understanding rather than working around.

The reason is that the plugin does more than attach to a language server. It sets up the client, and then it installs its own behaviour on top of that client: it runs a REPL, it evaluates snippets, it triggers Hoogle lookups, it may use fast-tags when the language server cannot provide tags, and it wires code lenses into the keymaps. If lspconfig also creates and configures a client for the same server, there are two clients attached to the same buffers, and which one owns a given capability becomes a matter of ordering.

The code lens example makes this concrete. The keymap comment notes that haskell-language-server relies heavily on code lenses, so auto-refresh is enabled by default in the plugin. Auto-refresh means the lenses are recomputed as you type, which is a real cost on a large file, and it is exactly the kind of setting that two configurations would fight over.

There is also the detail about not setting `vim.g.haskell_tools` in the after/ftplugin file, because that file is sourced after the plugin is initialized. It sounds like a minor footnote, and it is really a warning about the order of operations in Neovim startup. A per-filetype file is sourced late, by which point the plugin has already read its configuration, so a value set there is ignored. A plugin that has to be set up before the editor finishes loading cannot be configured from a per-filetype hook, which is why the plugin tries to avoid needing configuration at all.

The result is a plugin that is convenient precisely because it is opinionated. If your workflow already has a language server client for Haskell configured through lspconfig, the plugin is the wrong choice, and the README would rather tell you that plainly than have you debug a conflict.

What the plugin is competing with, and when the baseline is enough

It is worth being explicit about the alternatives, because a Haskell developer in Neovim already has a working setup.

The baseline is nvim-lspconfig with the hls configuration. That gives you the language server features, and the plugin's own README concedes it is the lowest common denominator of LSP support and is probably enough if you are starting out. The cost of staying there is that a few Haskell-specific things stay out of reach. Hoogle lookup for the type signature of a definition is the clearest one, because it is a documentation search over the package database rather than a fact about the file in front of you. The REPL is the other, since toggling a GHCi session for the current package or buffer is not something a language server exposes.

There is also fast-tags, and the plugin treats it as a fallback for vim.lsp.tagfunc, which is the interesting case. When the language server cannot answer a tag request, the plugin can generate tags another way, so navigation keeps working rather than failing silently. The plugin lists fast-tags as optional, so this is a graceful degradation rather than a requirement.

The debugging path is separate again, with haskell-debugger and nvim-dap listed as optional dependencies, and the topic tags including dap and debug-adapter-protocol, so a debug adapter is a distinct integration from the language server one.

The honest way to decide is to count how many of the Haskell-specific things you actually use. A developer who only wants completion and hover can stay on lspconfig and lose nothing. A developer who wants Hoogle on the definition under the cursor, a REPL at the keystroke, and snippet evaluation without leaving the buffer is the person this plugin is for, and for them the cost of not having it is a shell command and a context switch each time.

The version requirement is the other decision point. Neovim 0.12 or newer is required now, and the answer for an older Neovim is to find the right major version in the changelog, which is work the plugin deliberately pushes onto the user rather than maintaining compatibility itself.

Editorial conclusion

Adopt haskell-tools.nvim if you write Haskell in Neovim and want the language server plus Hoogle lookup, a REPL and snippet evaluation configured for you without wiring lspconfig by hand. Do not adopt it if you are starting out with Haskell, because the README suggests nvim-lspconfig's hls setup is enough at that stage, and check first that you are on Neovim 0.12 or newer, since the plugin now requires it and older Neovim users need an earlier major version from the changelog.

Frequently asked questions

What does haskell-tools.nvim do?

It is a Neovim plugin that automatically configures the haskell-language-server builtin LSP client and integrates with other Haskell tools, including Hoogle signature search, a GHCi REPL, evaluation of code snippets, a Telescope extension and fast-tags support. It needs no setup call and has no dependency on lspconfig.

How do I install haskell-tools.nvim?

With Neovim's built-in plugin manager, using `vim.pack.add` with the source and a version range, with rocks.nvim using `:Rocks install haskell-tools.nvim`, or with lazy.nvim by declaring the plugin and setting `lazy = false` because the plugin does its own lazy loading. The README suggests pinning to tagged releases to avoid breaking changes.

Do I need haskell-tools.nvim if I am new to Haskell?

Probably not. The README says that if you are starting out with Haskell, nvim-lspconfig.hls is probably enough, because it provides the lowest common denominator of LSP support. The plugin is for people who want the additional features that are specific to Haskell tooling.

Which Neovim version does haskell-tools.nvim need?

Neovim 0.12 or newer is required. For versions compatible with older Neovim releases, the README points at previous major version bumps in the changelog, and the releases show the project at v11.0.0 following v10.0.1 and v10.0.0.

What can I do with the Hoogle and REPL features?

The Hoogle integration searches for the type signature of the definition under the cursor, which the keymap examples bind to ht.hoogle.hoogle_signature, and a local hoogle installation is recommended for better search performance. The REPL can be toggled for the current package or the current buffer, and closed with ht.repl.quit.

Is haskell-tools.nvim still being maintained?

The repository is not archived and the last push was on 2026-10-20. Recent releases are v11.0.0 from 2026-09-20, v10.0.1 from 2026-06-29 and v10.0.0 from 2026-06-06, and the plugin is GPL-2.0 licensed with a troubleshooting directory at the repository root.

Official sources

  1. Issues
  2. License: GPL-2.0
  3. mrcjkb/haskell-tools.nvim on GitHub
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mrcjkb-haskell-tools-nvim.svg)](https://hysenlabs.com/projects/mrcjkb-haskell-tools-nvim)

Was this useful?