Library / SDK
hazelgrove/hazel avatar
hazelgrove/hazel

Hazel asks the type checker what to write, and tells you in the hole

Hazel, a live functional programming environment with typed holes

1,174 stars71 forksReasonMIT

At a glance

What is it?
Hazel is a live functional programming environment rooted in type theory, where you can write a hole and the type checker tells you what has to go there. It is built in Reason and OCaml with a dune and opam toolchain, it runs as a browser IDE that cannot be opened from a file URL, and every branch pushed to GitHub gets its own build at hazel.org.
Who is it for?
Hazel is worth trying if you teach or learn functional programming and want the type system to carry more of the load, because typed holes turn a compile error into a specification and the built environment gives every branch a public URL. It is not a general purpose language to deploy, and it is not a tool to adopt casually, since the build needs a pinned OCaml 5.2.0 toolchain, opam and npm, and the web side needs a server rather than a file.
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 1 day ago.
What is it written in?
Mainly Reason, 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 hole is a question the type system can answer

Hazel is described as a live functional programming environment rooted in the principles of type theory, and the interesting idea is what it does with an unfinished program. In a conventional language, writing a stub is a guess, and the compiler tells you that the type is wrong, which is much less than telling you what was intended. In Hazel, a hole is a first class part of the program, and the type checker works out the type of the hole and what it must produce. That is the whole pedagogical claim of the project, and it is why the environment is built as an IDE rather than a compiler you invoke. The project roots itself in academic work, with the relevant papers and more motivation linked from the Hazel website, and the repository history shows why, with two tagged artifacts from the POPL 2019 artifact evaluation process in 2018, and then a Hazel 3 release in July 2025. The primary language of the repository is listed as Reason, with OCaml and Elm among the topic tags, so the implementation is a typed language on top of the OCaml ecosystem rather than a new compiler from scratch.

Building it needs a pinned OCaml, opam and npm

The short version of the build is four commands, and the prerequisites are stated precisely. You need ocaml version 5.2.0, at least version 2.0 of opam, a recent version of npm, and your GitHub SSH keys set up. Then:

bash
git clone [email protected]:hazelgrove/hazel.git
cd hazel
make deps
make dev

If those prerequisites do not hold, the README points to INSTALL.md for the step by step version, which is the kind of instruction that saves an afternoon when the OCaml version is off by a patch. The dependency step is not a simple install. The Makefile adds the opam archive repository, updates it, installs from the locked dependency file with the test and doc components, runs npm install, and then runs a setup-zarith target that copies a vendored BigInt runtime into the opam library directory. The comment on that target explains why, that the vendored runtime uses native JavaScript BigInt from zarith_stubs_js 0.17.0, which survives structured clone, unlike the BigInteger.js library used in older versions, and the runtime is needed to fix WebWorker postMessage serialisation. That is a small, specific piece of engineering that tells you the project has been running in browsers for a while.

It has to be served, not opened

Running Hazel locally has one hard requirement that is easy to get wrong. You have to serve it on localhost or at some other non-file URL, because you cannot run it from a file:/// URL due to browser restrictions, for example on web workers. If you have python3 on your path, the built in Python server is available through make serve, and then you navigate to http://0.0.0.0:8000/ in your browser. If you would rather have hot reloading, make hot does that instead of make serve. And if you want to use some other server, make echo-html-dir prints the directory that needs to be served. The Makefile confirms the shape of that, with HTML_DIR pointing at _build/default/src/web/www and SERVER set to http://0.0.0.0:8000/. The web worker restriction is not an accident of the implementation. A live environment that evaluates code as you type needs workers, and workers do not run from a file URL, so the constraint is inherent to what Hazel is.

Every branch gets a public URL

The build server is a feature in its own right, and it is how most people should try the project. Every branch that has been pushed to GitHub and successfully builds can also be accessed at https://hazel.org/build/<branch_name>, once the GitHub action has finished building and deployed it, and the dev branch is the main branch at the moment, with a direct link to it. The same URL pattern works for the online editor at https://hazel.org/build/dev. This is a genuine difference in approach from a research prototype that lives on one developer's machine, because it means a paper reviewer, a student or a collaborator can open the exact commit you are talking about, and it makes the repository's CI a publishing pipeline rather than just a test run. The CI workflow badge at the top of the README and the codecov badge alongside it are the visible evidence of that pipeline, and the fact that the build server needs a successful CI run is what keeps it from becoming an open deployment service.

The Makefile is the project's own documentation

Reading the Makefile tells you what the project actually is, in a way the short README does not. The target list is long and specific. There are dev, dev-helper and dev-student targets, and setup-instructor and setup-student targets that copy different settings files for the exercise environment, which is how the same code base serves a teacher and a learner. There are watch and watch-release targets, and separate test, test-quick, watch-test and coverage targets with a generate-coverage-html companion, and a ci family with ci-quick, ci-check and ci-extended variants, which is a sensible way to trade a fast inner loop against a thorough one. There are lint-css and update-css-defaults targets, a dead-code family with dead-code, dead-code-json and dead-code-summary, and a fmt target driven by an.ocamlformat file at the root. The presence of a dead-code target in a language research project says something about its priorities, because in a type theory setting the type checker finds the dead code, and being able to list it is a research tool as well as a maintenance one.

The opam lock file is maintained by hand

One Makefile target is a good example of how a research tool stays reproducible. The change-deps target updates the opam repository, builds the package with dune, installs the dependencies with the test and doc components, runs opam lock to regenerate the lock file, and then edits that file with sed to remove the host- lines, which are architecture specific. The comment explains why it is not using the portable form of the in-place edit, and links a discussion of the sed command behaving differently on macOS and Linux. The result is a hazel.opam.locked file that pins the dependency versions without pinning the host architecture, which is exactly the compromise you want for a project that people build on both macOS and Linux. The repository is a dune project, with dune-project and dune-workspace at the root, a hazel.opam file for the package definition, a vendor/ directory, and the source under src/ with a CLI whose README is separate, plus test/, bench/, docs/, scripts/ and a run_tests script.

Who this is for, and where it stops

The audience is visible in the repository rather than declared in the README. INSTRUCTORS.md, a CONTRIBUTORS.md, the setup-instructor and setup-student targets and the exercise settings all point to teaching being a first class use, and a .changetours/ directory suggests guided walkthroughs of the codebase. The bench/ directory and the coverage targets point to performance and correctness work on the compiler side, and agent-docs/ suggests the project is being worked on with machine assistance. The limits are equally visible. The README carries a TODO comment about including screenshots or animated GIFs once the UI stabilizes, which is a plain statement that the interface is not finished. The environment is a browser IDE with a served origin and web workers, so it is not something you can embed in a script or run headless without work. And the language itself is a research vehicle, with the version numbering still at Hazel 3 in 2025, which tells you how far from a stable general purpose language it is. The licence is MIT with a LICENSE file and a licenses/ directory, and the project asks contributors to contact Cyrus Omar about their plans before starting, and offers a Slack for non-trivial contributions.

Editorial conclusion

Hazel is worth trying if you teach or learn functional programming and want the type system to carry more of the load, because typed holes turn a compile error into a specification and the built environment gives every branch a public URL. It is not a general purpose language to deploy, and it is not a tool to adopt casually, since the build needs a pinned OCaml 5.2.0 toolchain, opam and npm, and the web side needs a server rather than a file. Before you invest time, read the papers linked from the project site, run make deps and make dev once to see whether the toolchain fits your machine, and treat the browser build server as the low-friction path, since it needs none of the local setup and still gives you a live environment to click through.

Frequently asked questions

What are typed holes in Hazel?

A hole is a placeholder in the program that the type checker reasons about, so the environment can tell you what a value of that type has to be rather than only reporting a type mismatch. Hazel is a live functional programming environment rooted in type theory, built around that idea, with the relevant papers linked from hazel.org.

How do I build Hazel from source?

You need ocaml 5.2.0, opam 2.0 or newer, a recent npm and your GitHub SSH keys. Then run git clone [email protected]:hazelgrove/hazel.git, cd hazel, make deps and make dev. If the prerequisites do not apply, INSTALL.md has the step by step instructions.

Why can I not open Hazel with a file:// URL?

You have to serve it on localhost or another non-file URL, because of browser restrictions on web workers, which a live environment needs. Use make serve for the built in Python server, make hot for hot reloading, or make echo-html-dir to find the directory to serve with your own server.

How can I try Hazel without building it?

Every branch pushed to GitHub that builds successfully is published at https://hazel.org/build/<branch_name>, and the dev branch is the main branch at the moment. The README links the online editor at https://hazel.org/build/dev, and there is a Hazel CLI executable for basic terminal tasks described in the CLI README.

Official sources

  1. hazelgrove/hazel on GitHub
  2. License: MIT
  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/hazelgrove-hazel.svg)](https://hysenlabs.com/projects/hazelgrove-hazel)

Was this useful?