README.org

March 19, 2026 · View on GitHub

#+title: mkSpagoDerivation #+author: James Leslie [[https://img.shields.io/badge/built%20for-PureScript-1d222d.svg]][[https://img.shields.io/github/license/jeslie0/mkelmderivation.svg]][[https://img.shields.io/github/actions/workflow/status/jeslie0/mkSpagoDerivation/run_tests.yaml.svg]][[https://img.shields.io/github/v/release/jeslie0/mkSpagoDerivation.svg]]

This Nix flake provides an unopinionated approach to packaging [[https://github.com/purescript/purescript][PureScript]] projects with the [[https://github.com/NixOS/nixpkgs][Nix]] package manager. This project works by treating a PureScript project's =spago.lock= as a single source of truth for dependencies and extracting the required information from [[https://github.com/purescript/registry][PureScript's registry]].

  • Table of contents :toc:
  • [[#examples][Examples]]
  • [[#caching-dependency-build-artefacts][Caching dependency build artefacts]]
  • [[#out-of-date-registry][Out of date registry]]
  • [[#limitations][Limitations]]
  • [[#notes][Notes]]
    • [[#hooks][Hooks]]
  • [[#related][Related]]
  • [[#license][License]]
  • Examples The most important function that this flake provides is the mkSpagoDerivation function, exposed as both an output and via an overlay. This provides a wrapper around stdenv.mkDerivation which puts all of your project's dependencies in the right place, making it easy for you to build your projects in a reproducible way.

Importantly, the =spago.lock= file is required for mkSpagoDerivation to determine your project's dependencies. Optionally, if you provide your project's =spago.yaml= file, then your project's name will be extracted and used. You can provide a =name= or =pname= argument instead.

Here is a simple =flake.nix= that builds a PureScript project. #+begin_src nix { inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; flake-utils.url = "github:numtide/flake-utils"; mkSpagoDerivation.url = "github:jeslie0/mkSpagoDerivation"; ps-overlay.url = "github:thomashoneyman/purescript-overlay"; };

outputs = { self, nixpkgs, flake-utils, mkSpagoDerivation, ps-overlay }: flake-utils.lib.eachDefaultSystem ( system: let pkgs = import nixpkgs { inherit system; overlays = [ mkSpagoDerivation.overlays.default ps-overlay.overlays.default ]; }; in { packages.default = pkgs.mkSpagoDerivation { spagoYaml = ./spago.yaml; spagoLock = ./spago.lock; src = ./.; nativeBuildInputs = [ pkgs.purs-unstable pkgs.spago-unstable pkgs.esbuild ]; version = "0.1.0"; buildPhase = "spago bundle"; installPhase = "mkdir out;cpindex.jsout; cp index.js out"; buildNodeModulesArgs = { npmRoot = ./.; nodejs = pkgs.nodejs; }; }; } ); } #+end_src

The only attribute mkSpagoDerivation requires is src. The spagoYaml attribute will default to =src/spago.yaml=andlikewise, spagoLock defaultsto={src}/spago.yaml= and likewise, ~spagoLock~ defaults to ={src}/spago.lock=. Everything else is passed into mkDerivation.

Some Spago projects have dependencies from NPM. To automatically take care of fetching NPM packages, the buildNodeModulesArgs attribute allows specifing an argument set that is passed to the [[https://nixos.org/manual/nixpkgs/unstable/#javascript-buildNpmPackage-importNpmLock.buildNodeModules][importNpmLock.buildNodeModules]] function. This will build a =node_modules= directory for use in the derivation. See the [[./tests/nodeModulesTest][nodeModulesTest]] for an example. This attribute is completely optional and can be left out of the =mkSpagoDerivation= arguments if no node_modules directory is required.

There are no assumptions about the which version of the compiler is used - you must specify which copy of Spago and PureScript you want to use. Dependencies can be added through buildInputs or nativeBuildInputs. The following example demonstrates this, by using [[https://github.com/aristanetworks/purescript-backend-optimizer][purescript-backend-optimizer]] and using the unstable PureScript compiler from the PureScript Overlay. #+begin_src nix { inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; flake-utils.url = "github:numtide/flake-utils"; ps-overlay.url = "github:thomashoneyman/purescript-overlay"; mkSpagoDerivation.url = "github:jeslie0/mkSpagoDerivation"; };

outputs = { self, nixpkgs, flake-utils, ps-overlay, mkSpagoDerivation }: flake-utils.lib.eachDefaultSystem ( system: let pkgs = import nixpkgs { inherit system; overlays = [ mkSpagoDerivation.overlays.default ps-overlay.overlays.default ]; }; in { packages.default = pkgs.mkSpagoDerivation { spagoYaml = ./spago.yaml; spagoLock = ./spago.lock; src = ./.; version = "0.1.0"; nativeBuildInputs = [ pkgs.esbuild pkgs.purs-backend-es pkgs.purs-unstable pkgs.spago-unstable ]; buildPhase = "spago build && purs-backend-es bundle-app --no-build --minify --to=main.min.js"; installPhase = "mkdir out;cprmain.min.jsout; cp -r main.min.js out"; }; } ); } #+end_src

Some other useful functions are exposed. One is buildDotSpago, which builds a project's =.spago= directory. It takes an attribute set { spagoLock, src }, which respectively are the paths to the project's spago.lock and the root of the project. Another useful function is buildSpagoNodeJs, which builds the =spago-nodejs= directory, typically located in the user's =.cache= directory.

  • Caching dependency build artefacts mkSpagoDerivation is unopinionated and allows for a user to customise the way they build their projects. As projects get larger and require more dependencies, rebuilding all of them can add a lot of wasted time to nix builds. Spago does allow for caching the build artefacts for a project's dependencies and this can be integrated into a nix build. The general approach is to create a separate derivation that whose source is only the =spago.yaml= and =spago.lock= files, using spago install as the build phase. An example of this can be found in the [[file:tests/cache/default.nix][cache test]].

  • Out of date registry It is possible for this repository to not have the most up-to-date registry set. If you cant wait for the GitHub action to update this repository, you can override the =registry= and =registry-index= inputs to this flake. #+begin_src nix { inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; flake-utils.url = "github:numtide/flake-utils"; ps-overlay.url = "github:thomashoneyman/purescript-overlay"; mkSpagoDerivation = { url = "github:jeslie0/mkSpagoDerivation"; inputs = { registry.url = "github:purescript/registry/066f77d3b668fd7916e0af493d8d8ec7a850d774"; registry-index.url = "github:purescript/registry-index/53cfacb3b1677120eb5e6c11a1f2449d1049c2ce"; }; }; };

    outputs = { self, nixpkgs, flake-utils, ps-overlay, mkSpagoDerivation }: ... #+end_src

  • Limitations At the time of writing, this project only supports PureScript projects that make use of the newer spago@next releases. In particular, the project needs a spago.yaml file and a spago.lock file is required too.

  • Notes ** Hooks The buildPhase and installPhase always run =pre= and =post= hooks, even if the commands provided by the user don't specify them.

  • Related

  • License All of this repository is under the MIT license.