Purescript Backend for Lua

June 24, 2026 ยท View on GitHub

Purescript Lua CI

๐Ÿ”‹ Status: (2024-04-20) the project is in the "ready to be experimented with" state (read: it likely contains bugs but is already usable).

๐Ÿ’ก If you have an idea on how to use Purescript to Lua compilation please contribute it here: https://github.com/purescript-lua/purescript-lua/discussions/categories/ideas

Features

  • Lua code bundling: emits either a Lua module (a file that returns a table with functions) or an application (a file that executes itself).
  • FFI with Lua.
  • Dead Code Elimination (DCE).
  • Code inlining.
  • Package Set for PureScript/Lua libs.
  • All core libs added to the package set.

Quick Start

For the moment the best way to start is to use nix to intall pslua.

Consider configuring Cachix as a binary nix cache to avoid rebuilding a ton of dependencies:

cachix use purescript-lua

You can use this template repository to initialize your project.

Here is an another example project: Nginx server running Lua code using OpenResty.

If you use Spago to build your PureScript project, configure pslua as a custom backend in spago.yaml. The package set is the published Lua package set (the registry baseline with the Lua FFI forks overlaid), consumed via workspace.packageSet.url. Assuming pslua is on your PATH:

spago.yaml
package:
  name: acme-project
  dependencies:
    - effect
    - prelude
workspace:
  packageSet:
    url: https://github.com/purescript-lua/purescript-lua-package-sets/releases/download/psc-0.15.15-20260624/packages.json
  backend:
    cmd: pslua
    args:
      - --foreign-path
      - .
      - --ps-output
      - output
      - --lua-output-file
      - dist/main.lua
      - --entry
      - Main.main

With a backend configured, Spago compiles the project to CoreFn and then runs the backend command, so spago build links the result into dist/main.lua. spago run additionally executes the entry point: Spago invokes pslua --run Main.main, which compiles and runs it with lua, forwarding lua's exit code. (--run needs an application entry point <Module>.<binding>.)

Using nix with flakes

nix run 'github:purescript-lua/purescript-lua' -- --help

Installation

If you're on a x86 64bit Linux system then you can download a pre-built executable from the releases page:

wget -c https://github.com/purescript-lua/purescript-lua/releases/download/0.1.1-alpha/pslua-linux_x86_64.tar.gz -O - | tar -xz

alternatively,

Using nix with flakes

nix profile install 'github:purescript-lua/purescript-lua'

will make pslua executable available for use.

Windows

Nix build won't work on Windows so you'd first need to install cabal and ghc-9.8.4 (One way of installing those is GHCUp).

Once the pre-requisites are available on your PATH you run

cabal install exe:pslua

.... elided ....

Installing   commutative-semigroups-0.1.0.1 (lib)
Installing   primes-0.2.1.0 (all, legacy fallback)
Installing   base16-bytestring-1.0.2.0 (lib)
Installing   quiet-0.2 (lib)
Completed    newtype-0.2.2.0 (lib)

.... elided ....

Starting     pslua-0.1.0.0 (exe:pslua)
Building     pslua-0.1.0.0 (exe:pslua)
Installing   pslua-0.1.0.0 (exe:pslua)
Completed    pslua-0.1.0.0 (exe:pslua)
Copying 'pslua.exe' to 'C:\cabal\bin\pslua.exe'

This will build and install executable pslua.exe

C:\cabal\bin\pslua --help
pslua - a PureScript backend for Lua

Usage: pslua.exe [--foreign-path FOREIGN-PATH] [--ps-output PS-PATH]
                 [--lua-output-file LUA-OUT-FILE] [-e|--entry ENTRY]

  Compile PureScript's CoreFn to Lua

Available options:
  --foreign-path FOREIGN-PATH
                           Path to a directory containing foreign files.
                           Default: foreign
  --ps-output PS-PATH      Path to purs output directory.
                           Default: output
  --lua-output-file LUA-OUT-FILE
                           Path to write compiled Lua file to.
                           Default: main.lua
  -e,--entry ENTRY         Where to start compilation.
                           Could be one of the following formats:
                           - Application format: <Module>.<binding>
                             Example: Acme.App.main
                           - Module format: <Module>
                             Example: Acme.Lib
                           Default: Main.main
  -h,--help                Show this help text