Install GHC and the required toolchain for miso development
Miso compiles to WebAssembly or JavaScript using GHC. You need a GHC that supports one of these backends. The standard ghc you may already have installed does not support either target — you need a cross-compiler.
The miso team recommends using the WebAssembly backend as the default compilation target.
GHCup is the recommended way to install GHC for new Haskell users. It can install both the WASM and JavaScript cross-compilers.First, install GHCup if you do not already have it:
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
Then follow GHCup’s third-party channel instructions to add the WASM compiler. See the official ghc-wasm-meta README for the exact steps.
Nix can provide both the WASM and JavaScript compilers without requiring GHCup. It is the recommended approach for reproducible builds and CI.Install Nix:
The WASM backend is relatively new and not every Haskell package in the ecosystem supports it yet. You may need to use patched packages from time to time, which is why --allow-newer is passed to cabal.
Update your cabal.project to target the WASM compiler:
cabal.project
packages: .with-compiler: wasm32-wasi-ghcwith-hc-pkg: wasm32-wasi-ghc-pkgsource-repository-package type: git location: https://github.com/dmjio/miso branch: masterif arch(wasm32) -- Required for TemplateHaskell. When using wasm32-wasi-cabal from -- ghc-wasm-meta, this is superseded by the global cabal.config. shared: True
Configuration is affected by the following files:- cabal.projectResolving dependencies...Build profile: -w ghc-9.12.2.20250327 -O1In order, the following will be built (use -v for more details): - app-0.1.0.0 (exe:app) (configuration changed)Configuring executable 'app' for app-0.1.0.0...Preprocessing executable 'app' for app-0.1.0.0...Building executable 'app' for app-0.1.0.0...[1 of 1] Compiling Main ( Main.hs, dist-newstyle/build/wasm32-wasi/ghc-9.12.2.20250327/app-0.1.0.0/x/app/build/app/app-tmp/Main.o )[2 of 2] Linking dist-newstyle/build/wasm32-wasi/ghc-9.12.2.20250327/app-0.1.0.0/x/app/build/app/app.wasm
A .wasm binary cannot be opened directly in a browser. You need to create a hosting directory that includes the WASM payload, a JavaScript FFI shim, and an HTML loader.
Use an up-to-date Node.js version (tested with v24.2.0) to ensure post-link.mjs runs correctly.
Step 1 — Create the output directory and generate the FFI shim:
# Create the directory for hostingmkdir -v app.wasmexe# Produce ghc_wasm_jsffi.js, which makes GHC's JavaScript FFI work$(wasm32-wasi-ghc --print-libdir)/post-link.mjs \ --input $(wasm32-wasi-cabal list-bin app --allow-newer) \ --output app.wasmexe/ghc_wasm_jsffi.js# Copy the .wasm payload into the hosting directorycp -v $(wasm32-wasi-cabal list-bin app --allow-newer) app.wasmexe
Configuring executable 'app' for app-0.1.0.0...Preprocessing executable 'app' for app-0.1.0.0...Building executable 'app' for app-0.1.0.0...[1 of 1] Compiling Main ( Main.hs, dist-newstyle/build/javascript-ghcjs/ghc-9.12.2/app-0.1.0.0/x/app/build/app/app-tmp/Main.o )[2 of 2] Linking dist-newstyle/build/javascript-ghcjs/ghc-9.12.2/app-0.1.0.0/x/app/build/app/app.jsexe
Starting up http-server, serving /home/user/app/dist-newstyle/build/javascript-ghcjs/ghc-9.12.2/app-0.1.0.0/x/app/build/app/app.jsexehttp-server version: 14.1.1...Available on: http://127.0.0.1:8080Hit CTRL-C to stop the server
Open http://127.0.0.1:8080 in your browser to view the application.