Open-source project
haskell/vscode-haskell avatar
haskell/vscode-haskell

vscode-haskell: the VS Code bridge to haskell-language-server

VS Code extension for Haskell, powered by haskell-language-server

597 stars99 forksTypeScriptNOASSERTION

At a glance

What is it?
The Haskell extension for Visual Studio Code is a thin client for haskell-language-server, adding toolchain management through GHCup, formatter selection, multi-root support and a documented machine-overridable path setting. Most behaviour lives in the server, not here.
Who is it for?
Adopt vscode-haskell if you write Haskell in VS Code and want the language server's features without assembling the toolchain by hand, and skip it if you are happy in a different editor or need features the server does not implement, such as jump to definition for code outside the workspace.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly TypeScript, 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

A client for a server that does the real work

The Haskell extension for Visual Studio Code is described in one line as a VS Code extension for Haskell, powered by haskell-language-server. The README immediately qualifies that: almost all features are provided by the server, so it suggests reading the server's documentation for the interesting parts.

That framing matters for what you can expect from this repository. The feature list in the README is essentially the server's feature list, presented through an editor. Warning and error diagnostics come from GHC, type information and documentation appear on hover, there is code completion, document symbols, reference highlighting, module name suggestions for insertion or correction, and call hierarchy support. There is also a code lens for explicit import lists, code evaluation with its own tutorial, integration with retrie for codemodding, and generation of functions from type signatures with intelligent completion of holes using Wingman tactics.

The one feature the README flags as limited is jump to definition, which currently works only for local code definitions, with an upstream issue linked for the rest.

So the decision to use this extension is largely a decision to use haskell-language-server, with the extension contributing the editor integration, the toolchain handling and the configuration surface.

GHCup is the prerequisite, and the extension will not install it

The setup section is short and the constraint is explicit. The extension comes with batteries included and can manage your Haskell Language Server installations for you, powered by GHCup, but installation of GHCup itself cannot happen automatically. If you want the extension to manage HLS installations, you have to follow the GHCup installation instructions yourself, and the README adds a note to make sure you have a working ghcup installation before launching the extension.

The requirements section then breaks the toolchain down by project type, and this is the part worth internalising before you install anything.

For standalone .hs and .lhs files, ghc must be installed and on the PATH, with ghcup named as the easiest route. For Cabal based projects, both ghc and cabal-install must be installed and on the PATH, installable through ghcup or through Chocolatey on Windows. For Stack based projects, stack must be installed and on the PATH, and it must be configured to use GHC binaries installed by GHCup.

There is an alternative to all of that: you can let the extension manage your entire toolchain automatically, and you are asked on first startup, via ghcup, which should be pre-installed.

One install edge case is called out. If you are installing from an offline VSIX file, you also need to install language-haskell after installation, either from the marketplace or offline. That is a packaging detail, but it bites people who distribute the extension in locked-down environments.

Formatting is a choice of backend, not a fixed style

Formatting support is not hardcoded to one tool. The README lists formatting via Brittany, Floskell, Fourmolu, Ormolu or Stylish Haskell, which is the right call for Haskell, where a single canonical style has never existed and the community splits between the Haskell community style and the fourmolu family of opinions.

The selection lives in the extension's configuration as a setting with a fixed set of enum values, and the package.json shows the shape of it. The property is haskell.formattingProvider, with a scope of resource, a type of string and an enum listing brittany, floskell, fourmolu and the rest.

The scope value is the interesting detail. Because the formatter setting is scoped to resource rather than to the user or the window, a project can declare which formatter it wants in its own configuration, and that choice travels with the repository. For a team, that is the difference between a formatter that is a matter of personal taste and one that is part of the project's contract.

The linting side is separate. The README describes integration with hlint, described as the most used Haskell linter, to show diagnostics and apply hints via apply-refact.

The server path setting is machine overridable, and that is a documented risk

There is one configuration option in this repository that the README explicitly flags as a security concern, and it is worth reading rather than skimming.

If your server is manually installed and not on your path, you can set the path to the executable yourself.

json
"haskell.serverExecutablePath": "~/.local/bin/haskell-language-server"

A few placeholders are expanded. The tilde, and the ${HOME} and ${home} variants, expand into the user's home folder, while ${workspaceFolder} and ${workspaceRoot} expand into the current project root.

Then comes the warning, and it is specific. The option has machine-overridable scope, so it can be changed per workspace. The reasoning given is that this supposes it could be used to execute arbitrary programs, by adding a .vscode/settings.json in the workspace folder with this option set to an appropriate path. Issue 387 is linked for details.

The threat is straightforward. Opening an untrusted repository and accepting its workspace settings can point the extension at a different executable, which then runs with your permissions. The mitigation is not exotic: set the path yourself in your own user settings, or keep the server on your PATH so the setting is never needed. Machine-overridable means the repository can override the machine scope, so a workspace value wins over what you set at the machine level, which is exactly why the workspace you open matters.

What the extension contributes beyond the server

Looking at the package manifest makes the extension's own contributions clearer. The engine requirement is vscode ^1.102.0, so a recent Visual Studio Code is needed. The extension declares three languages: haskell for .hs files, cabal for .cabal files and literate haskell for .lhs files, and it activates on all three language identifiers.

Multi-root workspace support is called out in the feature list and the README has a dedicated section for it, which matters for polyglot repositories where a Haskell package sits next to other services.

The manifest also carries an extensionPack entry, haskell.language-haskell, which means the companion extension is pulled in automatically from the marketplace rather than needing separate installation. That is the same companion the offline VSIX instructions ask you to install by hand, so the packaging just automates it in the normal case.

The categories list the extension under Programming Languages, Formatters and Linters, which reflects the three distinct jobs it does: editing Haskell, formatting it with a backend of your choosing, and surfacing hlint diagnostics.

One piece of the repository is worth pointing out for anyone who wants to understand how releases are produced: there is a GenChangelogs.hs script at the root and a Changelog.md, so the release notes are generated rather than written by hand, alongside a flake.nix and flake.lock for the Nix-based toolchain.

The failure modes the troubleshooting list expects

The README's table of contents lists a troubleshooting section, and the headings inside it are the most honest description of what goes wrong with this setup in practice.

The first item points you to issues and tips in the haskell-language-server project, which is an admission that most problems live upstream rather than in this extension. The second is restarting the language server, which is the standard first response when the server state has gone stale.

The third is a specific error message: Failed to get project GHC version on darwin M1 with stack. That is a platform and toolchain interaction rather than a general failure, and it is the kind of thing you will only discover by hitting it.

The fourth is GHC ABIs don't match, which is the classic Haskell toolchain problem: the GHC version in use by the server and the one used to build the project have to line up, and when they do not, the symptom is an ABI error rather than a clear message. The fifth is using an old configuration, and the sixth is Stack, Cabal or GHC not being found, which is the PATH requirement from the setup section surfacing at runtime.

Taken together, these headings say something useful about this project: the extension is thin, the hard parts are in the Haskell toolchain, and most of what you will debug is the interaction between GHCup, Cabal or Stack, and the server, rather than the editor glue.

Editorial conclusion

Adopt vscode-haskell if you write Haskell in VS Code and want the language server's features without assembling the toolchain by hand, and skip it if you are happy in a different editor or need features the server does not implement, such as jump to definition for code outside the workspace. Before you trust it in a workspace you open, read the machine-overridable warning on haskell.serverExecutablePath and set that key yourself rather than inheriting it, and note the last push was on 2026-10-12 with release 2.8.3 on 2026-10-08.

Frequently asked questions

Do I need to install GHCup before using the Haskell extension for VS Code?

Yes, if you want the extension to manage your Haskell Language Server installations. The extension comes with batteries included and manages HLS through GHCup, but GHCup installation cannot happen automatically and the README asks you to have a working ghcup before launching the extension.

Which formatters can the Haskell extension in VS Code use?

Formatting is available through Brittany, Floskell, Fourmolu, Ormolu or Stylish Haskell, and the formatter is chosen with the haskell.formattingProvider setting, which is scoped to the resource so a project can pin its own choice.

What is the risk with the haskell.serverExecutablePath setting?

It has machine-overridable scope, so a workspace can override it with a .vscode/settings.json pointing at a different executable, which the README says could be used to execute arbitrary programs. Set the path in your own settings and keep the server on your PATH if you want to avoid the issue.

What do I need installed for a Cabal or Stack based Haskell project?

Cabal projects need both ghc and cabal-install on the PATH, installable through ghcup or Chocolatey on Windows. Stack projects need stack on the PATH, configured to use GHC binaries installed by GHCup.

What causes the Failed to get project GHC version error with stack?

The README's troubleshooting section names it specifically as a problem on darwin M1 with stack, and points to issues and tips in the haskell-language-server project for the underlying cause, since most problems with this setup live in the server rather than the extension.

Official sources

  1. haskell/vscode-haskell on GitHub
  2. Issues
  3. Project website
  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/haskell-vscode-haskell.svg)](https://hysenlabs.com/projects/haskell-vscode-haskell)

Was this useful?