Home

Step-by-Step Guide to Installing GHC-JS (Haskell JavaScript FFI) + Example

Table of Contents

Introduction

In this blog, I’ll walk you through installing and using the JavaScript Foreign Function Interface (FFI) in Haskell with GHC. This setup lets talk to Javascript from Haskell and vice versa, making it a powerful tool for web development or integrating Haskell with JavaScript-based platforms. Most resources I found online were outdated, so I’ve created this up-to-date guide based on my own experience to help you get started.

Prerequisites

I’m using a Linux machine (Ubuntu 22.04), but these instructions should work on other platforms like macOS or Windows with minor adjustments. You’ll need Node.js installed. If you don’t have it, I recommend using nvm to install the latest LTS version:

$ nvm install --lts

Verify the installation:

$ node --version
# Expected output: v20.12.2 (or similar LTS version)

Install GHC

The easiest way to install GHC and its tools is with GHCup. Run this command to install it:

$ curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

After installation, you can use the Text User Interface (TUI) to manage GHC versions:

$ ghcup tui

This opens an interface showing available GHC, Cabal, and Stack versions. However, these standard GHC builds don’t include the JavaScript backend—we’ll enable that next.

Add Cross Channel

To enable the JavaScript backend, we need to add the cross release channel in GHCup. Release channels provide access to specialized GHC builds, including those for cross-compilation targets like JavaScript and wasm. Add it with:

$ ghcup config add-release-channel cross

Now, running ghcup tui will show additional GHC versions, including those with JavaScript support. See the GHCup documentation for more details.

Install Emscripten

The JavaScript backend requires Emscripten, a toolchain for compiling to JavaScript and WebAssembly. The latest Emscripten version caused issues in my tests, so I recommend version 3.1.57, which works reliably with GHC’s JavaScript backend. Install it like this:

git clone https://github.com/emscripten-core/emsdk.git
$ cd emsdk
$ ./emsdk install 3.1.57
$ ./emsdk activate 3.1.57
$ source ./emsdk_env.sh

The source command sets up environment variables for Emscripten. Verify it’s working with emcc --version.

Set Alias for GHCJS

After installing the GHC JavaScript backend, set it as the default GHC version:

$ emconfigure ghcup install ghc javascript-unknown-ghcjs-9.10.0.20240413
$ ghcup set ghc javascript-unknown-ghcjs-9.10.0.20240413

For convenience, add an alias to your shell configuration file (e.g., .bashrc or .zshrc):

$ alias ghcjs=javascript-unknown-ghcjs-ghc 

Run

source ~/.bashrc
to apply the alias.

Example

Screenshot of running the GHCJS example

References