GHC 9.10.1-alpha3 is now available

The GHC developers are very pleased to announce the availability
of the third alpha release of GHC 9.10.1. Binary distributions, source
distributions, and documentation are available at

We hope to have this release available via ghcup shortly.

GHC 9.10 will bring a number of new features and improvements, including:

  • The introduction of the GHC2024 language edition, building upon
    GHC2021 with the addition of a number of widely-used extensions.

  • Partial implementation of the GHC Proposal #281, allowing visible
    quantification to be used in the types of terms.

  • Extension of LinearTypes to allow linear let and where

  • The implementation of the exception backtrace proposal, allowing the annotation of exceptions with backtraces, as well
    as other user-defined context

  • Further improvements in the info table provenance mechanism, reducing
    code size to allow IPE information to be enabled more widely

  • Javascript FFI support in the WebAssembly backend

  • Improvements in the fragmentation characteristics of the low-latency
    non-moving garbage collector.

  • … and many more

A full accounting of changes can be found in the release notes.
As always, GHC’s release status, including planned future releases, can
be found on the GHC Wiki status.

This alpha is the penultimate prerelease leading to 9.10.1. In two weeks
we plan to publish a release candidate, followed, if all things go well,
by the final release a week later.

We would like to thank GitHub, IOG, the Zw3rk stake pool,
Well-Typed, Tweag I/O, Serokell, Equinix, SimSpace, the Haskell
Foundation, and other anonymous contributors whose on-going financial
and in-kind support has facilitated GHC maintenance and release
management over the years. Finally, this release would not have been
possible without the hundreds of open-source contributors whose work
comprise this release.

As always, do give this release a try and open a ticket if you see
anything amiss.


May I suggest a wider gap between a release candidate and the final release? Many people will only starting testing 9.10 once RC1 is out, and it’s unlikely we get much building just in a week.

I know that historically X.Y.1 is treated essentially as a release candidate. I think we all can save resources by giving more time to test RC1 instead.


Technically, distributors are free to interpret it that way and are also free to skip releases entirely.

1 Like

Can we please not cut any release for GHC 9.10 while head.hackage is still required? Having that leak out of GHC’s internal development is a terrible idea. The fact that it’s even required for testing alphas is highly questionable imho. It should be exclusively reserved for in-flight HEAD of GHC. Not for release candidates and even less for releases.

I know that at least these packages don’t build with 9.10. I wonder if anyone has a more comprehensive list of packages that were broken with 9.10.

EDIT: To clarify, because @hasufell highlighted that this could be misread. I do not expect the whole ecosystem to catch up prior to a release. But I expect that those libraries that were already patched as part of GHC’s smoke testing (and thus necessitating head.hackge) to be properly patched and on hackage, at the time, or prior of the official release). That is, head.hackage should never be needed to make something compile, that otherwise wouldn’t for release (candidate) compilers.


I think we need to be a bit more precise about our expectations here.

Do we expect GHC HQ to handle ecosystem migration for a new release? Certainly not. Their valuable time should go into compiler development.

The question is why were those patches in head.hackage in the first place? Are they required for some parts of the test suite? Can we use the new release without it?

I’m fairly negative on the idea of promoting a possibly unreviewed set of patches for end users. But that’s merely a documentation concern.

My expectation is pretty simple: I do not want to see any proliferation of head.hackage outside of GHC development. This will be cargo culted all over the place and at some point every cabal.project file will include hackage + head.hackage. head.hackage at the point of a release should be an empty set. The patches put into head.hackage leading up to a release must be in released versions by the time a release is cut. Yes this will need someone to take charge of this and clear out head.hackage leading up to a release. Hence my question if we know which patches are required for 9.10 still?

Ideally we’d have something like a table:

| GHC version | head.hackage patch | Upstream patch | state (patch, reviewed, merged, release) |
| ----------- | ------------------ | -------------- | ---------------------------------------- |

and someone (ideally from the HF I think) to be in charge of driving this. Maybe @Kleidukos or @chreekat feel up to that?


This creates a hard dependency between release process and random hackage package maintainers.

From a release management perspective, that’s a disaster and will likely involve hackage trustee processes for abandoned packages (there’s one from hvr in your list), which is naturally slow.


Apparently, you can’t compile GHC with itself (failing at hadrian stage):

Warning: Unknown/unsupported 'ghc' version detected (Cabal supports
'ghc' version < 9.10): /root/.ghcup/bin/ghc is version
Resolving dependencies...
Error: cabal: Could not resolve dependencies:
[__0] trying: ghc-platform- (user goal)
[__1] trying: base- (dependency of ghc-platform)
[__2] trying: hadrian- (user goal)
[__3] trying: hadrian:+selftest
[__4] trying: QuickCheck-2.14.3 (dependency of hadrian +selftest)
[__5] next goal: splitmix (dependency of QuickCheck)
[__5] rejecting: splitmix- (conflict: base==,
splitmix => base>=4.3 && <4.20)
[__5] skipping: splitmix-, splitmix-, splitmix-,
splitmix-, splitmix-0.1, splitmix-0.0.5, splitmix-0.0.4,
splitmix-0.0.3, splitmix-0.0.2, splitmix-0.0.1, splitmix-0 (has the same
characteristics that caused the previous version to fail: excludes 'base'
[__5] fail (backjumping, conflict set: QuickCheck, base, splitmix)
After searching the rest of the dependency tree exhaustively, these were the
goals I've had most trouble fulfilling: base, QuickCheck, splitmix, hadrian,
hadrian:selftest, ghc-platform
Try running with --minimize-conflict-set to improve the error message.

@facundominguez or @RyanGlScott, do you know why there are so many patches in head.hackage? If it’s only supposed to be for enabling building HEAD, it seems odd that there are patches going back to 2019 in there.


I think trying to upstream patches more from head.hackage before a release and keeping track of the status of patches both sound like good ideas. Though I’m somewhat sceptical that it would be worth blocking a release over this stuff.

At the end of the day, stuff like this boils down to capacity. Redundant patches get removed when someone realises and makes an MR. head.hackage could always benefit from more people writing patches, from more people using them, and from more people upstreaming and tracking the status of upstreamed patches.

Though it doesn’t always make sense to expect upstream patches to be released before a GHC release:


A couple of questions:

  1. In what way do you anticipate head.hackage proliferating outside of GHC development?
  2. What are the changes to GHC that are causing these packages to need to be patched?

Several packages with head.hackage patches are no longer maintained (e.g., FPretty and critbit). As such, their head.hackage patches have never been removed, as there haven’t been new Hackage releases that would render the patches obsolete.

Arguably, we should remove these patches after a certain amount of time has passed, although I haven’t found the time to do so. Contributions would be welcome here.


So what makes a patch/package go into head.hackage? Are there strict criteria? What is the main use case precisely?

6 posts were split to a new topic: head.hackage usage

Unofficial GHC JS cross bindists have been built by me for this release (provisional platform/distro support):

And they’ve been added to the ghcup-cross-0.0.8.yaml channel: Add javascript-unknown-ghcjs- by hasufell · Pull Request #203 · haskell/ghcup-metadata · GitHub

To try, you first need emscripten:

git clone
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./

Then install the GHC cross via ghcup:

ghcup config add-release-channel
emconfigure ghcup install ghc --set javascript-unknown-ghcjs-

Then do some hello-world:

echo 'main = putStrLn "hello world"' > hello.hs
javascript-unknown-ghcjs-ghc -fforce-recomp hello.hs

Also see


The main use-case of head.hackage as far as I’m concerned is to facilitate testing of GHC. For better or worse, source changes sometimes are needed to build projects with GHC HEAD. head.hackage exists to collect these patches in one place so that we (and possibly our users) can readily test their projects against the compiler.

I proposed to extend the mandate of head.hackage to address end-user migration explicitly in the ghc.X.hackage proposal although there was little appetite in the community for this. Ultimately I think this is fine; we all agree that it would be better if we rather tried to minimize the need for head.hackage.

I agree with @hasufell that we cannot create a dependency between the GHC release process and the updating of the ecosystem. Managing a GHC release is already very tricky, with far too many “known unknowns” which make adhering to a concrete schedule a challenge. Adding yet more such constraints to the process would make the process significantly more costly than it already is.


The primary motivation for the short gap between release candidate and final is to maintain the original final release date despite having pushed back alpha2 by a week. In principle the alpha series exists released specifically to allow for a wide range of testing early, giving us plenty of time to address issues before the final release. However, I recognize that we often don’t see much vigorous testing until later in the series. Consequently, perhaps it would be preferable to err on the side of giving more time to the late alphas and release candidates.

All of this is to say, I would be fine with moving the final release back by a week to allow more time to testing.

1 Like

Like alpha2, if you want to use with Stack:

  1. Upgrade to the master branch version of Stack (can be used only if you are not using GHCup to manage versions of Stack): stack upgrade --source-only --git.

2A. If you are not using GHCup to manage versions of GHC, augment Stack’s default setup-info dictionary in a configuration file (needed only until Stack has fetched the compiler once). For example, on Windows:

        # Can be extended with SHA protections etc: see

2B. If you are using GHCup to manage versions of GHC, augment ~/.ghcup/config.yaml. For example:

  - StackSetupURL
  - setup-info:

            # Can be extended with SHA protections etc: see
  1. Specify the compiler in a Stack configuration file (eg stack.yaml):
compiler: ghc-

Fascinatingly, GHCup also allows to mix the stack metadata with any GHCup metadata channel.

E.g. if you want the stack logic for bindists + ghcup logic for prereleases, you can do:

  - StackSetupURL 

No need to write your own setup-info dictionary.

1 Like

I’m afraid you are tired of my usual rant, but community at large does not care whether a release is a week or even a month later. There are significant costs to pay for each minor GHC release: ghcup has to support it, parsers and exact printers have to be updated, hls has to support it and make a new release, Docker images, Stackage, Stack, Haskell-CI, haskell-actions/setup, etc. There is no point to incur all these costs for the sake of an artificial deadline.

Since alpha releases do not guarantee to be feature-full and more breakage can be introduced before release, maintainers should not relax build-depends bounds or make new releases of their packages until RC is out. It is expected that almost no testing outside of root packages happens until RC1.

Maybe you want to adjust the nomenclature of GHC releases and mark, say, alpha3 as RC1? This is assuming you can guarantee that no further breakage is happening afterwards.

A gap of two weeks between RC1 and 9.10.1 means that maintainers have essentially one weekend to test, adjust and release everything. I’d rather release 9.10.1 as RC2 and then make 9.10.1 in time when you’d normally do 9.10.2.