Nixbot is a continuous integration (CI) service for the Nix ecosystem, shipped as a single NixOS service. It is a rewrite of buildbot-nix, its spiritual ancestor.
What started as a set of Buildbot plugins now runs standalone. One server handles forge webhooks, nix-eval-jobs evaluation, builds through the local nix daemon (offloaded via remote builders), commit statuses, and its own web frontend.
Chat with us on Matrix: #nixbot:thalheim.io
- Fast, Parallel evaluation using nix-eval-jobs
- Gitea/Github integration:
- Login with GitHub to control builds
- CI status notification in pull requests and on the default branch
- Embeddable SVG build-status badges for READMEs
- All builds share the same nix store for speed
- Tested with large flakes (50k flake outputs per evaluation)
- The last attribute of a build is protected from garbage collection
- Build matrix based on
.#checksplus theherculesCIonPush jobs of your flake - No arbitrary code runs outside of the Nix sandbox
- hercules-ci effects to run impure CI steps i.e. deploying NixOS, with dependency ordering and named locks
To set up nixbot, start by exploring the provided examples:
- Check out the basic setup in example.
- The NixOS module lives in nixosModules/nixbot.nix.
- For local development, see Local Development Guide.
Additionally, you can find real-world examples at the end of this document.
The service runs on one machine; to support multiple architectures and to scale out builds, configure nix remote builders. For a practical NixOS example, see this remote builder configuration.
Nixbot replaces the buildbot master/worker pair with a single service. See the migration guide for the full upgrade instructions.
Nixbot automatically triggers builds for your project under these conditions:
- When a pull request is opened.
- When a commit is pushed to the default git branch.
It evaluates the .#checks attribute of your project's flake in parallel; each
attribute results in a separate build step (named
default.checks.<system>.<name>). You can test these builds locally using
nix flake check -L or
nix-fast-build.
If your flake also defines a herculesCI output (by hand or via
hercules-ci-effects),
nixbot additionally follows
hercules-ci-agent's evaluation
semantics: every
onPush.<job>.outputs attribute is built (named <job>.<path>),
outputs.effects run as effects, ciSystems filters
per-system outputs, and the buildDependenciesOnly, noBuildPhase,
ignoreFailure and requireFailure build modifiers are honored.
If you need to build other parts of your flake, such as packages or NixOS
machines, add them to onPush.<job>.outputs or re-export them into the
.#checks output. Here are two examples to guide you:
- Using flake-parts.
- A plain flake example.
Anonymous users get read-only access to public projects; private repositories
and their builds are only visible to users with access on the forge. For write
actions (restart, cancel) a login is required. Every enabled forge with OAuth
credentials configured offers a login, OIDC via services.nixbot.oidc.enable;
several providers can be active at once.
We have the following roles:
- Admins (hard-coded in the NixOS configuration): reload the project list, enable/disable projects, restart/cancel any build.
- Repo writers (forge write access): restart/cancel that repository's builds.
- PR authors: restart/cancel their own pull request's builds.
Nixbot uses GitHub App authentication to integrate with GitHub repositories. This enables automatic webhook setup, check-run reporting (with a working Re-run button), and secure authentication.
See the GitHub documentation for setup instructions.
Nixbot integrates with Gitea using access tokens for repository management and OAuth2 for user authentication. This enables automatic webhook setup, commit status updates, and secure authentication.
See the Gitea documentation for setup instructions.
Token-based integration with per-repository webhooks and commit status updates.
See the GitLab documentation for setup instructions.
Nixbot supports generic OpenID Connect (OIDC) authentication, allowing you to use any OIDC-compliant identity provider (Keycloak, PocketID, Authentik, etc.) for user login.
See the OIDC documentation for configuration details.
Currently nixbot will look for a file named nixbot.toml (falling back to the
legacy buildbot-nix.toml) in the root of whichever branch it's currently
evaluating, parse it as TOML and apply the configuration specified. The
following table illustrates the supported options.
| key | type | description | default | example | |
|---|---|---|---|---|---|
| lock file | lock_file |
str |
dictates which lock file nixbot will use when evaluating your flake |
flake.lock |
have multiple lockfiles, one for nixpkgs-stable, one for nixpkgs-unstable or by default pin an input to a private repo, but have a lockfile with that private repo replaced by a public repo for CI |
| attribute | attribute |
str |
which attribute in the flake to evaluate and build | checks |
using a different attribute, like hydraJobs |
| flake_dir | flake_dir |
str |
which directory the flake is located | . |
using a different flake, like ./tests |
| effects on pull requests | effects_on_pull_requests |
bool |
run hercules-ci effects on pull requests | false |
set to true to run effects on PRs |
| effects branches | effects_branches |
list[str] |
glob patterns for additional branches that run effects | [] |
["staging", "release/*"] |
By default, effects only run on the default branch. The effects_branches and
effects_on_pull_requests settings are always read from the default
branch's nixbot.toml (via git show) so that pull request authors cannot
grant themselves effects access.
⚠️ Security warning: PR effects receive the sameeffects_per_repo_secretsas default-branch effects. A malicious PR can modify the effect code to exfiltrate these secrets. Only enableeffects_on_pull_requestsfor repositories where you trust all contributors, or where no secrets are configured.
Nixbot serves an SVG build-status badge for the latest build on a branch:
https://<nixbot-host>/repos/<forge>/<owner>/<repo>/badge.svg
It reports the default branch unless ?branch=<name> is given. Embed it in a
README with:
[](https://<nixbot-host>/repos/github/<owner>/<repo>)Private repositories return 404 to anonymous requests, so status is never exposed.
To access the build results on other machines there are two options at the moment
You can set up a binary cache on the CI machine to make its nix store accessible from other machines. Check out the README of the project, for an example configuration
Nixbot also supports pushing packages to cachix via the services.nixbot.cachix
options.
Nixbot does not have native support for pushing packages to attic yet. However it's possible to integrate run a systemd service as described in this example configuration. The systemd service watches for changes in the local nix store and uploads the contents to the attic cache.
See docs/EFFECTS.md for CLI usage, flake reference support, and secrets configuration.
The lix overlay overrides nix-eval-jobs with a version that doesn't work with nixbot because of missing features and therefore cannot be used together with the nixbot module.
Possible workaround: Don't use the overlay and only set the
nix.package = pkgs.lix; NixOS option.
- Garnix - Fully hosted, zero-config CI for flakes.
- Hercules CI - Hosted CI with self-hosted agents. Nixbot's effects system is inspired by theirs.
- Hydra - The original Nix CI, powers nixos.org. Written in Perl, not recommended for new deployments.
See Nixbot in action in these deployments:
- Mic92's dotfiles: Configuration | Instance
- Nix-community infra: Configuration | Instance
- Technical University Munich: Configuration | Instance
For commercial support, please contact Mic92 at joerg@thalheim.io.