ghcid keeps a GHCi session alive and prints the errors, and refuses to be an IDE
Very low feature GHCi based IDE
At a glance
- What is it?
- ghcid is a Haskell tool that opens ghci, reloads it whenever your sources change, and formats the result into a fixed height console that shows the current errors and warnings. It deliberately does not integrate with editors, does not give you access to the ghci it starts, does not depend on GHC as a library and does not start web servers, and its own FAQ argues with the fuller alternatives by name.
- Who is it for?
- ghcid suits a Haskell developer who wants the error list from a real ghci session in a small terminal pane, and who is content to run a separate console next to the editor. It does not suit someone who wants a single window with completion, hovers and navigation, and it is the wrong tool for a project whose ghci session is slow to load or hard to configure.
- 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 22 days ago.
- What is it written in?
- Mainly Haskell, 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 deliberately small design point in a crowded space
ghcid is described as a very low feature GHCi based IDE, and the README states the design position before listing anything else. Either GHCi as a daemon, or GHC plus a bit of an IDE. To a first approximation it opens ghci and runs :reload whenever your source code changes, formatting the output to fit a fixed height console.
Then comes the list of what it does not do, and it is the most important paragraph in the document. Unlike other Haskell development tools, ghcid is intended to be incredibly simple: it does not integrate with any editors, does not provide access to the ghci it starts, does not depend on GHC the library and does not start web servers.
Each of those exclusions is a design decision with a reason behind it. Not integrating with editors is what makes it a console tool that works with any editor, including over SSH. Not giving access to the ghci session is what keeps the tool from becoming a REPL, and it is also the source of the most surprising limitation in the project, described later. Not depending on GHC the library is what lets it work with whatever GHC version your project uses.
The FAQ is where the philosophy is argued rather than asserted. Asked whether this is as good as a full IDE, the answer is that the author has gone for simplicity over features, that it is a point in the design space but not necessarily the best point for you, and it names the alternatives: ghcide, a real IDE in your editor, reflex-ghci, like ghcid but with more terminal UI features, and reflex-ghcide, a full IDE in the terminal.
The audience is a Haskell developer who already has a good ghci workflow and wants the error list continuously, rather than someone who wants a new editor.
The reload loop is the whole mechanism
There is no incremental compiler and no language server in the traditional sense here. ghcid starts ghci with a command you give it, watches the files that ghci has loaded, and runs :reload when they change. GHCi does the work of compiling and type checking, and ghcid does the watching and the presentation.
What you see on every save is the list of errors and warnings in the project. The example in the README is a compiler error with a suggestion:
Main.hs:23:10: Not in scope: `verbosit' Perhaps you meant `verbosity' (imported from System.Console.CmdArgs) Util.hs:18:1: Warning: Defined but not used: `foo'
and when nothing is wrong, the output is simply:
All good
The project notes that it uses ghci under the hood, so even relatively large projects should update their status pretty quickly. That speed comes partly from a trick that shows up later in the FAQ, where ghcid appends -fno-code to the command line, which makes the reload cycle about twice as fast, because ghci is then type checking without generating code.
The presentation detail that matters in daily use is the fixed height console. The output is formatted to fit a console of a set height rather than to scroll, which is why the README tells you to resize your console and make sure you can see it while working in your editor, and why on Windows you may want to pass --topmost so the console sits above all other windows, and on Linux you probably want your window manager to make it topmost or a tiling window manager to place it.
So the interaction is: one small terminal pane, always visible, that tells you the state of the build. It is a narrower thing than an IDE and a much cheaper one to run.
The command line is the contract with GHCi
Installation is the usual three routes for a Haskell tool:
stack install ghcid
brew install ghcid
cabal update && cabal install ghcidAnd then you run it with a command, which is how your project is started inside ghci:
ghcid "--command=ghci Main.hs"If you omit --command, ghcid picks a default, and the order of preference is specific and sensible. It will default to stack ghci if you have the stack.yaml file and the .stack-work directory, default to ghci if you have a .ghci file in the current directory, and otherwise default to cabal repl.
That is a chain of guesses about your build tool, and the author's own advice is to bypass the guessing. He says he always creates a .ghci file at the root of all his projects, which usually reads something like:
:set -fwarn-unused-binds -fwarn-unused-imports :set -isrc :load Main
Two more mechanisms reduce repetition. If you have a .ghcid file in the current folder, or a parent folder, its contents are used as command line arguments, so if you always want --command=custom-ghci you can put that in the file and stop writing it each time. And if you prefer, the --command value is where you point at whatever session you actually want.
The README is blunt about where the difficulty lies: to use ghcid you first need to get ghci working well for you, and in particular to craft a command line or .ghci file such that when you start ghci it has loaded all the files you care about, which you can check with :show modules. Getting ghci started properly is described as one of the hardest things of using ghcid, and while ghcid has a lot of defaults for common cases, it does not always work out of the box.
That is the honest bargain. ghcid does not make ghci work, it makes a working ghci continuously visible.
Evaluation flags, and the comment syntax nobody expects
Because ghcid manages the ghci session, you can evaluate expressions through it, and the README describes two ways.
The first is the --test flag, which takes any ghci expression and runs it whenever the code is warning free. Passing --warnings instead changes the trigger to the code being merely error free. So --test=:main is a way of running your main function on every clean build, which is a small thing that adds up in a project with a fast test entry point.
The second is --allow-eval, which lets comments in the source files run expressions after loading, with the syntax -- $> expr, and there is a blog post referenced for the details. Multiline comments are supported with a longer form:
{- $> expr1 expr2 ... exprN <$ -}
The idea is that you write the expression next to the code it exercises, and it runs on reload. This is a genuinely useful pattern for a REPL-driven workflow, and it is also the point where the design's exclusions start to bite.
The README warns that expressions which read from standard input are likely to hang, given that ghcid already uses the standard input to interact with ghci. That is a direct consequence of the tool not giving you access to the ghci it starts. If your expression needs to prompt for input, there is no session to type into, and the process blocks.
The evaluation surface is therefore deliberately narrow: expressions with no input, run at a moment of the project's choosing, with results going to the same fixed height console as the errors.
Editor plugins exist, but they are not the point
There are a few plugins that integrate ghcid into editors, and the README lists them: a VS Code extension, an nvim plugin in plugins/nvim/ in the repository, vim-ghcid-quickfix for vim, and an Emacs plugin in plugins/emacs/.
The presence of these is informative. ghcid does not integrate with any editors, yet the repository ships integrations, which tells you the division of labour. The tool produces a fixed height console and the plugin's job is to place it. The editor is not being driven by ghcid; ghcid is being displayed by the editor.
That is the opposite of the direction most modern tooling takes, where the language server is the core and the editor is a client. ghcid inverts it: ghci is the core, and the editor is optional.
The comparison in the FAQ is the clearest statement of the trade-off. ghcide is a real IDE in your editor. reflex-ghci is like ghcid but with more terminal UI features. reflex-ghcide is a full IDE in the terminal. And ghcid itself is the simplest of the four, which is a coherent position rather than an accident.
For a reader trying to place it, the deciding question is whether you want the tool or the environment. If you want a completion popup and a hover and a jump to definition, ghcid is not the project. If you want the compiler's opinion, continuously, in four lines of terminal, it is exactly the right size.
The FAQ documents the sharp edges, including the -fno-code trade
The FAQ is the most technically dense part of the README, and it is where a user will actually get stuck.
The pattern matching warning entry is the one with the most consequence. Ghcid automatically appends -fno-code to the command line, which makes the reload cycle about twice as fast. Unfortunately GHC 8.0 and 8.2 suffer from a bug which means -fno-code also disables pattern matching warnings. On those versions you either accept no pattern match warnings or use -c to specify a command line to start ghci that does not include -fno-code, and from GHC 8.4 the problem no longer exists.
That is a real trade, and the project is upfront about it. You get twice the reload speed in exchange for losing a class of warnings on two old compiler versions, and the fix is to give up the speed on those versions.
Other entries cover the file deletion case, where the answer is that yes, that is a bug in GHCi, and the workaround is to kill ghcid and start it again. The syntax highlighting entry suggests running the terminal in a buffer whose file type is set to Haskell in Neovim or Emacs, or piping ghcid through source-highlight with ghcid | source-highlight -s haskell -f esc.
The general commands entry is the one for a different problem. ghcid reloads ghci when the files ghci has loaded change, and if you want to run arbitrary commands when arbitrary files change, the README points at Steel Overseer, Watchman, feedback, Watchexec and entr, and explains that those are the tools for that job.
And the last one is a link to a list of general tips for using ghcid, which is where a user will find the day to day advice that the tool itself does not encode.
A small Haskell repository with a custom licence and a quiet release line
The repository is a conventional Haskell package layout. There is ghcid.cabal, Setup.hs, cabal.project, a src/ directory for the library, an app/ directory for the executable, a test/ directory, and a plugins/ directory holding the nvim and Emacs integrations. The.ghci file at the root is the author's own session setup and doubles as an example, and the dot files show the tooling:.hlint.yaml for the Haskell linter,.weeder.yaml for detecting unused code, and a.vscode/ directory.
Two files are more revealing than they look. There is a.env.example with a GCP project id and a Windows SSH password placeholder, and a script called ssh-windows-gcp.py, which together suggest the project's test infrastructure runs against a Windows machine reached over SSH, which is the obvious way to exercise a tool that behaves differently on Windows. And there is an AGENTS.md, alongside a PULL_REQUEST_TEMPLATE.md and a CHANGES.txt, which is a project set up to be worked on by both people and tooling.
On the legal side, the licence is a custom one that GitHub cannot classify, so the terms are in the LICENSE file and a reader has to look there. That is worth doing before using the tool in a commercial environment, since a permissive understanding is easy to assume and awkward to correct later.
On maintenance, the picture is mixed and should be read carefully. The repository is not archived and the last push was on 2026-10-01, so work is landing. The most recent published release is v0.8.9 from 2023-07-02, and the package is on Hackage and on Stackage's nightly, with a build status badge for the CI workflow. So the code is moving while the published version is a few years old, which is a normal pattern for a tool that depends on the ghci it wraps and on a Haskell toolchain whose versions keep moving.
Editorial conclusion
ghcid suits a Haskell developer who wants the error list from a real ghci session in a small terminal pane, and who is content to run a separate console next to the editor. It does not suit someone who wants a single window with completion, hovers and navigation, and it is the wrong tool for a project whose ghci session is slow to load or hard to configure. Verify first that you can get ghci itself to load everything you care about, since the README calls that the hardest part of using ghcid, and check the fixed height console behaviour on the display you will use, because the output is formatted to fit a set number of lines rather than to scroll.
Frequently asked questions
What is ghcid and how does it work?
It is a very low feature GHCi based IDE that opens ghci, runs :reload whenever your source code changes, and formats the output to fit a fixed height console showing the current errors and warnings. It uses ghci under the hood, so even relatively large projects should update their status pretty quickly.
How do I install and start ghcid?
Install it with stack install ghcid, brew install ghcid or cabal update && cabal install ghcid, then run it with a command such as ghcid "--command=ghci Main.hs". If you omit --command it defaults to stack ghci with a stack.yaml and .stack-work, to ghci with a .ghci file in the current directory, and otherwise to cabal repl.
Why am I not seeing pattern matching warnings in ghcid?
Ghcid appends -fno-code to the command line, which makes the reload cycle about twice as fast, but on GHC 8.0 and 8.2 that also disables pattern matching warnings because of a compiler bug. On those versions you either accept the missing warnings or use -c to start ghci without -fno-code, and from GHC 8.4 the problem no longer exists.
Can ghcid run expressions when I save?
Yes, with the --test flag you can pass any ghci expression, for example --test=:main, which runs whenever the code is warning free, or with --warnings for when it is merely error free. With --allow-eval, source comments such as -- $> expr are also run after loading, including multiline comments using the {- $> ... <$ -} syntax, though expressions reading standard input are likely to hang.
Does ghcid work with my editor?
ghcid itself does not integrate with any editors, but the repository ships integrations for Neovim and Emacs, and the README links plugins for VS Code and vim. The editor integration also depends on getting ghci itself right, since ghcid reloads only the files ghci has loaded.
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/ndmitchell-ghcid)Was this useful?