Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bun2Nix

Bun2nix Logo

Bun2nix is a fast rust based tool for converting lockfiles generated with the JavaScript Bun (v1.2+) package manager files to Nix expressions, which allows them to be consumed to build Bun packages reproducibly.

Advantages

Here are some of the advantages of using bun/bun2nix over the alternatives:

  • Much faster than other similar lang2nix tools for the javascript ecosystem - a full cached install will only take around 50ms for a medium project with 2k packages
  • Build aot complied binaries easily with bun that fit the nix model much better than npm scripts
  • Quality error messages because of the static types in rust

Alternatives

Here are some alternatives to bun2nix in the JavaScript ecosystem which fulfill a similar purpose:

Installation

Bun2nix is primarily distributed as a nix flake library that contains everything you need to package your bun application with the tool.

This can be setup in two ways:

From A Template

By default 2 templates are offered for starting off a new project with bun2nix enabled by default:

  • A minimal hello world binary program - the default.
  • A basic react website and server setup.

Notable files

The main files of note are:

  • flake.nix ⇒ Contains basic project setup for a nix flake for bun2nix
  • default.nix ⇒ Contains build instructions for this bun package
  • bun.nix ⇒ Generated bun expression from bun.lock
  • package.json ⇒ Standard JavaScript package.json with a postinstall script pointing to bun2nix

Default - Minimal Setup

To produce the default minimal sample, run:

nix flake init -t github:baileyluTCD/bun2nix

This is a bare-bones project created via bun init which produces a simple hello world binary packaged via bun2nix.

React Website

To start with the React website template run

nix flake init -t github:baileyluTCD/bun2nix#react

This is a simple example of a basic React app built through bun2nix.

In a pre-existing flake

To install bun2nix in an already existing bun project with a flake.nix, the following steps are recommended:

1. Source the bun2nix repo

Add the bun2nix flake to your inputs as follows:

bun2nix.url = "github:baileyluTCD/bun2nix";
bun2nix.inputs.nixpkgs.follows = "nixpkgs";

1.5. (Optional) Use the binary cache

The bun2nix executable typically takes a while to compile, which is typical for many rust programs, hence, because of the garnix based CI/CD, a convenient binary cache is provided.

To add it include the following in your flake.nix.

nixConfig = {
    extra-substituters = [
      "https://cache.nixos.org"
      "https://cache.garnix.io"
    ];
    extra-trusted-public-keys = [
      "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
      "cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g="
    ];
};

2. Add the binary to your environment

Next, add the bun2nix program into your developer environment by adding it to your devshell.

devShells.default = pkgs.mkShell {
  packages = with pkgs; [
    bun
    bun2nix.packages.${system}.default
  ];
};

NOTE: the system variable can be gotten in a variety of convenient ways - including flake-utils or nix-systems.

3. Use the binary in a bun postinstall script

To keep the generated bun.nix file produced by bun2nix up to date, add bun2nix as a postinstall script to run it after every bun operation that modifies the packages in some way.

Add the following to package.json:

"scripts": {
    "postinstall": "bun2nix -o bun.nix"
}

4. Build your package with nix

Finally, a convenient package builder is exposed inside bun2nix - mkBunDerivation.

Add the following to flake.nix:

my-package = pkgs.callPackage ./default.nix {
    inherit (bun2nix.lib.${system}) mkBunDerivation;
};

And place this in a file called default.nix

{ mkBunDerivation, ... }:
mkBunDerivation {
  pname = "bun2nix-example";
  version = "1.0.0";

  src = ./.;

  bunNix = ./bun.nix;

  index = "index.ts";
}

A list of available options for mkBunDerivation can be seen at the building packages page.

The Command Line Tool

The recommended way to use bun2nix is by adding it to your package.json to automatically run after any package management option:

"scripts": {
    "postinstall": "bun2nix -o bun.nix"
}

However, if you run without the -o flag it will produce a text output over stdout similar to other lang2nix tools, hence if you enforce formatting rules in your repository it is likely a good idea to pass it through a formatter before writing the file.

Options

Currently, the options available from the command line tool are as follows:

Convert Bun (v1.2+) packages to Nix expressions

Usage: bun2nix [OPTIONS]

Options:
  -l, --lock-file <LOCK_FILE>      The Bun (v1.2+) lockfile to use to produce the Nix expression [default: ./bun.lock]
  -o, --output-file <OUTPUT_FILE>  The output file to write to - if no file location is provided, print to stdout instead
  -h, --help                       Print help
  -V, --version                    Print version

Building Packages

bun2nix provides a number of functions to aid building bun related packages:

Building with mkBunDerivation

mkBunDerivation is provided as a library function to build bun packages from the file generated by the bun2nix command line tool.

Example

Currently, basic usage would look something like:

{mkBunDerivation, ...}:
mkBunDerivation {
  pname = "simple-bun-app";
  version = "1.0.0";

  src = ./.;

  bunNix = ./bun.nix;

  index = "index.ts";
}

or, in the more implicit style:

{mkBunDerivation, ...}:
mkBunDerivation {
  packageJson = ./package.json;
  src = ./.;
  bunNix = ./bun.nix;
}

NOTE: building with the implicit package.json values makes a number of basic assumptions about your project that it expects to hold true in the name of convenience. Approximately, these are:

  • name is a field that is acceptable for use as the name of the binary produced by your package.
  • version is a field denoting your package version in proper semantic versioning.
  • module is a field pointing towards your index.ts file or equivalent. If you notice any strange errors while using the implict build scheme try specifying the values manually and contribute a new descriptive assert message to mkBunDerivation`.

Arguments

The full list of accepted arguments is:

ArgumentPurpose
packageJson(Optional) Your project's package.json. If supplied can be used to complete pname, version and index instead of requiring them manually.
pname(Optional) The name of the package to build. Required if packageJson is not given.
version(Optional) Your package version. Required if packageJson is not given.
srcThe source code for your package
bunNixThe file generated by the bun2nix cli
index(Optional) The index.{js,ts} file entry point to your bun application. If you do not have one, leave this empty and use a custom buildPhase. This should be a string containing the relative path from src. Required if packageJson is not given.
buildFlagsOptional flags to pass into bun build in the default buildPhase. By default these flags are [ "--compile" "--minify" "--sourcemap" "--bytecode" ]. If you have issues with your build try removing some of them or read the bun documentation on single file executables.
dontPatchShebangs(Optional) Prevent patching shebangs in node_modules scripts.

writeBunScriptBin - Create Bun $ Shell Scripts

writeBunScriptBin is useful for creating once off $ Shell scripts, in a similar manner to writeShellScriptBin in nixpkgs.

Example

An example bun script for printing "Hello World" might look like:

writeBunScriptBin {
  name = "hello-world";
  text = ''
    import { $ } from "bun";

    await $`echo "Hello World!"`;
  '';
};

Arguments

The full list of accepted arguments is:

ArgumentPurpose
nameThe name to give the binary of the script
textTextual contents of the script

Create a valid node_modules directory with mkBunNodeModules

mkBunNodeModules is used by mkBunDerivation for producing the node_modules directory it links to before building the app. When passed the packages list produced by the bun2nix command line tool, it produces a fully valid node_modules directory as would be created by a fresh bun install.

Example

Example usage of mkBunNodeModules might look like:

  bunNix = import ./bun.nix;

  node_modules = mkBunNodeModules { packages = bunNix };

Arguments

The full list of accepted arguments is:

ArgumentPurpose
packagesThe contents of the bun.nix file.
dontPatchShebangs(Optional) Prevent patching shebangs in node_modules scripts.

By default, shebangs in scripts inside node_modules are patched to use bun instead of node. Use dontPatchShebangs = true; if you want to preserve the original shebangs (for example, to maintain compatibility with tools that expect Node.js).