hello — 90 seconds
A minimal Haskell-to-WebAssembly "hello world" you can run under Node.js or
in a browser, built with the stable-haskell wasm cross-compiler + dual-compiler
cabal-install.
Download the template Browse files
Prerequisites
If you haven't already done the install steps, do them first. For convenience:
ghcup config add-release-channel \
https://stable-haskell.github.io/ghc/ghcup-wasm.yaml
ghcup install ghc wasm32-wasi-9.14.0.stable.1
ghcup install cabal 3.17.0.0.stable.0
ghcup set cabal 3.17.0.0.stable.0
Plus Node.js 22+ on $PATH.
Build and run
curl -L -o hello.tar.gz https://stable-haskell.github.io/ghc/examples/stable-haskell-wasm-hello.tar.gz
tar xf hello.tar.gz && cd stable-haskell-wasm-hello
export PATH="$HOME/.ghcup/ghc/wasm32-wasi-9.14.0.stable.1/bin:$PATH"
make build # cabal build via the wasm cross-compiler
make run-node # post-link + node run.mjs → prints "Hello from the WASM reactor!"
make run-web # post-link + serve public/ → http://localhost:8000
make clean # remove build artifacts
make help (the default target) shows all targets.
What's interesting in here
myapp.cabal— the WASM-onlyghc-optionsblock sets up the WASI reactor pattern:-no-hs-main+-optl-mexec-model=reactor+-optl-Wl,--export=hs_start. The host JS callshs_start()instead of the wasm running its own_start.cabal.project— declares the dual-compiler form:with-build-compiler: ghc(native) forSetup.hsand TH host;with-compiler: wasm32-unknown-wasi-ghcfor the actual package code.app/Main.hs—foreign export javascript "hs_start" main :: IO ()is the surface that the JS host invokes.run.mjs/public/index.js— the reactor bring-up sequence:wasi.initialize→__ghc_wasm_jsffi_init→hs_start. All three steps are mandatory; skipping__ghc_wasm_jsffi_inityields "RTS is not initialised; call hs_init() first".Makefile— wirespost-link.mjs(ships in~/.ghcup/ghc/wasm32-wasi-9.14.0.stable.1/lib/targets/wasm32-unknown-wasi/lib/) into the build so you don't have to remember the path. OverrideWASM_VERSIONif you need a different one.
Want more?
Step up to the miso-counter template — same recipe, but
with 50+ Template-Haskell-heavy deps (aeson, lens, jsaddle, miso)
exercising the full dyld + JSFFI link chain at real-world scale.
License
Apache-2.0.