Open-source project
Mic92/nix-fast-build avatar
Mic92/nix-fast-build

nix-fast-build pipelines Nix evaluation and building instead of queueing them

Combine the power of nix-eval-jobs with nix-output-monitor to speed-up your evaluation and building process.

561 stars43 forksPythonMIT

At a glance

What is it?
Mic92/nix-fast-build evaluates Nix attributes with nix-eval-jobs, starts building each one the moment its evaluation finishes, and renders the logs itself, with optional remote execution over SSH.
Who is it for?
Adopt nix-fast-build if you evaluate large flakes or NixOS machine sets locally or in CI and the serial build queue is what costs you time, and start with the plain `nix-fast-build` invocation against `.#checks`. Skip it if your expression set is small enough that evaluation finishes instantly, and do not reach for `--file` mode expecting remote builds, since remote building is not supported there.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Serial evaluation is what makes a big flake slow

nix-fast-build exists to remove one specific bottleneck from Nix workflows: the gap between evaluating an attribute and starting to build it. Evaluating and building big flakes, meaning NixOS machine sets with many attributes, is slow when each attribute is handled one after another. The README uses the disko integration test suite as the illustration, citing a rebuild that demands 1:50 minutes on an AMD Ryzen 9 7950X3D against 10 seconds with nix-fast-build. That is the project's own figure for its own case, not a general guarantee, and the gap it describes comes from concurrency rather than from a cleverer compiler.

The audience is therefore people who already use Nix and already feel this. A maintainer checking a dozen NixOS configurations, a CI job that evaluates every machine in a flake, someone iterating on a large set of packages. The tool does not replace nix-eval-jobs or the Nix build system, and it does not change what your expressions evaluate to. It changes when the work starts and how you watch it.

Builds start while evaluation is still running

The mechanism is a pipeline rather than a faster step. Under the hood, nix-fast-build takes the output of nix-eval-jobs to evaluate flake attributes in parallel. The part that matters is what happens next: as soon as an attribute finishes evaluating, nix-fast-build initiates its build, even while the overall evaluation continues. Nothing waits for the full attribute set to be known.

That is the whole trick, and it explains why the speedup shows up on workloads with many attributes. A long evaluation on one attribute no longer stalls the builds of the attributes that are already resolved. The optional fourth stage is also part of the same pipeline: once a build finishes, nix-fast-build can start uploading it to a designated remote binary cache, so a successful artefact is on its way out before the last build has even started.

Two execution modes share this pipeline. In the default flake mode, the command evaluates all systems in `.#checks` and builds the attributes in `.#checks.$currentSystem`. In file mode it does the same work over a plain Nix expression, which the README notes works with both flakes and plain expressions. The starting point in a flake project is a single command:

console
$ nix-fast-build

If the tool is not on your PATH, the README gives the one-shot form, which fetches the project and runs it in place:

console
$ nix run github:Mic92/nix-fast-build

The log renderer parses nix's internal-json stream directly

nix-fast-build draws its own build output. It parses nix's internal-json log stream, which the README says is compatible with both Nix and Lix, and it no longer depends on nix-output-monitor. The legacy flag `--no-nom` survives from the days when that flag disabled nix-output-monitor, and forcing it now selects the non-interactive renderer.

On a terminal you get an interactive view. Running builds occupy a region at the bottom of the screen while verdicts and failure extracts scroll into the normal scrollback above it. Pressing `f` opens a browser over the logs of failed and running builds, where `j`, `k`, `Enter` or digits select an entry and `/` filters the list. The `d` key toggles between opening a log in `$PAGER` and dumping it into scrollback, and running builds are followed live through `less +F`.

The design choice worth noting is that the parsing is done inside the tool rather than by a separate monitor process. That keeps the log stream and the build state in one place, and it means the project depends on an internal log format rather than on a stable public interface.

In CI each build emits one contiguous log block

Without a terminal, output is shaped for a log collector. Each build's log is emitted as a single contiguous block when it finishes, so concurrent builds never interleave into an unreadable file. On GitHub, Forgejo and Gitea Actions, successful build logs are folded with `::group::` markers, which the `--no-fold` flag turns off. Failed builds are never folded, so a failure stays visible in the CI interface.

There is also a stall detector. A heartbeat lists running builds every 30 seconds, and a build that produces no output for `--stall-timeout` seconds, 300 by default, has its last lines dumped and is switched to live streaming. That default is a real behavioural difference from a plain build log: a build that goes quiet for five minutes is not treated as hung, it is surfaced.

The result is that a CI log for a parallel build reads as a sequence of whole build reports rather than a jumble of interleaved output, which matters most when a job runs many checks and one of them fails.

File mode is impure by default and cannot build remotely

Not every project is a flake. The `--file` flag points nix-fast-build at a plain Nix expression, for example `./release.nix`, and passing `--file` with no argument falls back to `default.nix`. Attribute selection works the way `nix-build -A` does, through `-A`, and expression arguments come through `--arg` and `--argstr` while the Nix search path is extended with `-I`.

The command form is the same shape as the flake one:

console
$ nix-fast-build --file ./release.nix

Passing arguments to the expression, and pointing the search path at a flake, look like this:

console
$ nix-fast-build --file ./release.nix --argstr system x86_64-linux
$ nix-fast-build --file ./ci.nix -I nixpkgs=flake:nixpkgs

A specific attribute can be selected with `-A`, in the manner of `nix-build -A`:

console
$ nix-fast-build --file ./release.nix -A mypackage

One default deserves attention. Evaluation in file mode is impure by default, which is what allows `builtins.getFlake` and `<nixpkgs>` to resolve, and `--pure` is there to enforce strict pure evaluation when a reproducible result matters. This is a meaningful difference from flake mode, and a CI job that assumes pure evaluation in file mode will get different behaviour than it expects.

The limit of file mode is remote work. The README states that remote building with `--remote` is not supported in `--file` mode, because there is no flake archive mechanism to upload arbitrary Nix expressions to a remote machine. If your evaluation lives in a standalone expression file and your compute lives elsewhere, those two facts do not meet.

Remote mode uploads the flake, not the sources

The remote path runs the whole pipeline on another machine. The argument is an SSH target, passed after `--remote`, and the user on the remote endpoint must already recognise you as a trusted user for the feature to work at all. The README gives the invocation as:

bash
nix run github:Mic92/nix-fast-build -- --remote youruser@yoursshhostname

Replace the placeholder with your own SSH login credentials for the target machine.

What gets transferred is the point of difference. The README notes that with the remote-builder protocol, uploading pre-built paths or sources from the local machine often becomes the bottleneck, and nix-fast-build does not use that protocol. Instead it uploads only the flake and performs evaluation and building on the remote end, then downloads the finished builds back to the local machine without having to pull all build dependencies in between. The saving is bandwidth rather than time, since the work still happens remotely.

There is a second, narrower option. `--store` dispatches builds to a Nix store URL while evaluating locally, and results are copied back into the local store when a build finishes, or left remote with `--no-download`. It uses the Nix store protocol only, cannot be combined with `--remote`, `--copy-to` or the upload flags, and it evaluates locally, which is a different trade from `--remote`.

The --skip-cached flag exists for CI without a persistent store

A CI-specific problem gets its own flag. By default `nix build` downloads pre-built packages, which means needless downloads even when nothing in a package changed. On a runner without a persistent Nix store, such as a GitHub Actions job, those downloads are paid on every run and can dominate the job's duration.

`--skip-cached` changes what nix-fast-build attempts. It ensures that only packages missing from the binary caches are built, so a check that has an upstream binary cache hit costs a fetch rather than a build. The README shows it in a workflow step:

yaml
- name: Build with nix-fast-build
  run: nix-fast-build --skip-cached

The trade is that a cached artefact is trusted rather than rebuilt. If your workflow needs to prove that a package compiles from source every time, this flag works against that goal, and the default behaviour is the one you want. If your goal is a fast signal on whether a change broke something, the flag is the difference between a two minute job and a ten minute one.

Job summaries are written on Gitea and Forgejo but not yet shown

When a summary environment variable is present, nix-fast-build writes a job summary into the CI interface. The summary carries the overall build status with success and failure counts, a detailed section per failed build including its logs, and collapsible sections for successful operations such as builds, evaluations and uploads. Logs for failed packages are fetched with `nix log`, and very long logs are truncated to the last 100 lines.

The variables that trigger this are `GITHUB_STEP_SUMMARY`, `GITEA_STEP_SUMMARY` and `FORGEJO_STEP_SUMMARY`. The catch is worth stating plainly: job summaries are fully supported in GitHub Actions, while Gitea and Forgejo set the environment variables but do not yet display the summary content in their interface. The file is still written, so it will appear once that support lands upstream.

The project itself is a Python package with a console entry point, version 2.0.4 in the pyproject metadata, released under the MIT licence. Its last push was on 2026-10-18, and recent releases include 2.0.4, 2.0.3 and 2.0.2 across September 2026.

Editorial conclusion

Adopt nix-fast-build if you evaluate large flakes or NixOS machine sets locally or in CI and the serial build queue is what costs you time, and start with the plain `nix-fast-build` invocation against `.#checks`. Skip it if your expression set is small enough that evaluation finishes instantly, and do not reach for `--file` mode expecting remote builds, since remote building is not supported there. Before switching a pipeline over, verify three things: that `nix-eval-jobs` is available in your environment, that the summary variables your CI provider sets are the ones you expect, since Gitea and Forgejo write the summary file but do not yet display it, and that any remote host you pass to `--remote` already trusts your account. The project was pushed to on 2026-10-18 and ships as version 2.0.4 under the MIT licence.

Frequently asked questions

How do I run nix-fast-build for the first time?

Run `nix-fast-build` in a flake project, or start it with `nix run github:Mic92/nix-fast-build`. The command evaluates all systems in `.#checks` concurrently and builds the attributes in `.#checks.$currentSystem`.

Can nix-fast-build work with a plain Nix expression instead of a flake?

Yes, pass `--file`, for example `nix-fast-build --file ./release.nix`, and with no file argument it defaults to `default.nix`. Evaluation in this mode is impure by default, and `--pure` enforces strict pure evaluation.

How do I run a build on a remote machine with nix-fast-build?

Use `nix run github:Mic92/nix-fast-build -- --remote youruser@yoursshhostname`. The remote endpoint must recognise you as a trusted user, and only the flake is uploaded so that evaluation and building happen entirely on the remote side.

What is the difference between --remote and --store in nix-fast-build?

`--remote` runs the whole pipeline over SSH, uploading the flake and executing evaluation and building remotely, while `--store` dispatches builds to a Nix store URL and evaluates locally. `--store` cannot be combined with `--remote`, `--copy-to` or the upload flags, and `--no-download` leaves results on the remote.

Why is my CI job downloading the same packages every run?

By default `nix build` downloads pre-built packages even when nothing changed, which is costly on runners without a persistent Nix store. The `--skip-cached` flag restricts builds to packages that are missing from the binary caches.

Official sources

  1. Issues
  2. License: MIT
  3. Mic92/nix-fast-build on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mic92-nix-fast-build.svg)](https://hysenlabs.com/projects/mic92-nix-fast-build)

Was this useful?