DEV Community

Dwayne Crooks
Dwayne Crooks

Posted on • Edited on

How I use Nix in my Elm projects

Nix is a tool that allows you to make reproducible development environments. I've started using it in all my Elm side projects and I've had a good experience with it thus far. To pique your curiosity I just wanted to share my simple setup that has been working quite well for me.

When I first started using Nix I used nix-shell with a shell.nix file but I've recently switched to Nix flakes which uses nix develop with a flake.nix file.

nix-shell

Here's an example shell.nix taken from my elm-7guis web application.

let
  pkgs = import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/7f256d7da238cb627ef189d56ed590739f42f13b.tar.gz") {};
in
pkgs.mkShell {
  packages = [
    pkgs.caddy
    pkgs.elmPackages.elm
    pkgs.elmPackages.elm-format
    pkgs.elmPackages.elm-optimize-level-2
    pkgs.elmPackages.elm-review
    pkgs.elmPackages.elm-test
    pkgs.nodejs_18
    pkgs.shellcheck
  ];

  shellHook =
    ''
    export project="$PWD"
    export build="$project/.build"

    export PATH="$project/bin:$PATH"
    '';
}
Enter fullscreen mode Exit fullscreen mode

When I run nix-shell at the root of the project it puts me in a Nix shell that contains, among other programs, caddy and shellcheck. Notice that in the shellHook I add the project's shell scripts to the PATH. So once I'm in the Nix shell I can, among other things:

  1. Serve the main application with Caddy using serve.
  2. Serve the prototype with Caddy using serve-prototype.
  3. Find any bugs in the shell scripts with ShellCheck using check.

In some projects I've wanted to use HTTPie to test APIs and jq to work with some JSON data. Nix has been really helpful in managing those dependencies that I can't easily get from npm.

nix develop

Here's an example flake.nix taken from my elm-integer library.

{
  description = "A developer shell for working on elm-integer.";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=23.11";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};
      in
      {
        devShells.default = pkgs.mkShell {
          name = "elm-integer";

          packages = with pkgs.elmPackages; [
            elm
            elm-doc-preview
            elm-format
            elm-optimize-level-2
            elm-test
            pkgs.caddy
            pkgs.nodejs_20
            pkgs.nodePackages.terser
            pkgs.shellcheck
          ];

          shellHook =
            ''
            export project="$PWD"
            export build="$project/.build"
            export PATH="$project/bin:$PATH"

            npm install --loglevel silent
            '';
        };
      }
    );
}
Enter fullscreen mode Exit fullscreen mode

I enter the Nix shell by running nix develop but the end result is similar to before, i.e. I get access to the dependencies you see listed in packages.

Conclusion

Nix has a steep learning curve, it takes a while to learn to use and even longer to understand, and it may not be needed for every Elm project. However, I hope that the little taste of Nix that I've given you has piqued your interests.

BTW, feel free to use my shell.nix or flake.nix files and tweak them to suit your needs.

Happy Nixing!

Top comments (2)

Collapse
 
improvement_addict profile image
Improvement Addict

Nice! I do the same with Guix. Natively supports Elm!
guix.gnu.org/manual/devel/en/html_...

Collapse
 
dwayne profile image
Dwayne Crooks

Interesting, I hadn't heard of Guix before. How long have you been using it? Would you recommend it over Nix?