Colmena: a stateless NixOS deployment tool for fleets of hosts
A simple, stateless NixOS deployment tool [maintainer=@stepbrobd, @NickCao, @zhaofengli]
At a glance
- What is it?
- Colmena is a Rust wrapper over Nix commands that builds and activates NixOS configurations across many machines in parallel, with tag-based host selection. It is thin by design, and that thinness is both its selling point and its limit.
- Who is it for?
- Adopt Colmena if you already run NixOS on the target machines, want a single hive.nix or colmenaHive output to describe them, and are comfortable with a tool that keeps no state and therefore offers no rollback. Do not adopt it if your hosts are not NixOS, if you need a state record of what was deployed when, or if you want the tool to manage the machines themselves rather than their configuration.
- 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 2 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Colmena solves, and for whom
Deploying one NixOS machine is a local operation. Deploying forty is a coordination problem: which hosts get which configuration, how the closures reach them, and what happens when one host is unreachable. Colmena exists to answer that. The README describes it as a simple, stateless NixOS deployment tool modeled after NixOps and morph, written in Rust, and it is aimed at people who already manage NixOS hosts and want the deployment step to be a thin layer over Nix rather than a system of its own.
The audience is narrow on purpose. Every target must be a NixOS machine reachable over SSH. If you run a mixed fleet of Debian and NixOS boxes, Colmena only covers the NixOS half. The README also states that Colmena should work with existing NixOps and morph configurations with minimal modification, which tells you who the intended migrant is: someone with a hive-shaped configuration already written and a reason to move off the older tool.
How the hive, the tags and the parallel apply fit together
The unit of configuration is a hive. In the non-flake workflow it is a hive.nix file; with flakes it is an outputs.colmenaHive produced by colmena.lib.makeHive. Both describe a set of hosts plus a meta block that pins Nixpkgs, and both support a defaults module imported by every host. Hosts are ordinary NixOS modules, so anything you can write in configuration.nix you can write here.
Selection is by tag. The README shows deployment.tags = [ "web" "infra-lax" ] and the corresponding invocation colmena apply --on @web, with glob matching available as colmena apply --on '@infra-*'. The sample output shows the tool reporting how many hosts it selected out of the total, which matters when a glob is broader than you intended.
Underneath, the README is explicit that Colmena is a thin wrapper over Nix commands such as nix-instantiate and nix-copy-closure, and that it supports parallel deployment. The Cargo.toml confirms the async stack: tokio with the rt-multi-thread feature, futures, async-stream and tokio-stream. That is the whole architecture. Colmena does not run an agent on the target and does not maintain a database of node state. It evaluates, builds, copies closures over SSH and activates. The word stateless in the description is not marketing; it is a statement about what the tool does not keep.
Installing Colmena and running a first apply
Colmena is in Nixpkgs beginning with 21.11, so the shortest path is a shell with the package in it. This drops you into an environment where the colmena command exists without touching your profile.
nix-shell -p colmenaIf you want the development version instead, the README gives a profile install from GitHub, or from a local clone. A Cachix binary cache at https://colmena.cachix.org holds unstable builds produced by GitHub Actions.
nix profile add github:nix-community/colmenaWith the command available, write a hive.nix in a directory. The minimal shape is a meta block pinning Nixpkgs and at least one host. The README recommends overriding meta.nixpkgs, and notes that meta.nodeNixpkgs can override it per node, which is useful when one host needs to track a different checkout.
{
meta = {
nixpkgs = <nixpkgs>;
};
host-a = { name, nodes, ... }: {
networking.hostName = name;
time.timeZone = nodes.host-b.config.time.timeZone;
};
host-b = {
deployment.targetHost = "host-b.mydomain.tld";
deployment.targetPort = 1234;
deployment.tags = [ "web" "infra-lax" ];
time.timeZone = "America/Los_Angeles";
};
}Two details in that snippet are worth noticing. Hosts can reference each other through the nodes argument, so host-a reads a value out of host-b's evaluated configuration. And the target address defaults to the attribute name, so host-b would normally be reached at host-b unless deployment.targetHost overrides it. The README also documents deployment.targetUser and the SSH_CONFIG_FILE environment variable for further SSH customization.
From the same directory, build without deploying, then apply. Running build first is the cheap way to catch an evaluation or build error before anything touches a remote machine.
colmena build
colmena apply --on @webWith flakes, the entry point moves into flake.nix as outputs.colmenaHive, and the same two commands run from the flake directory. The README's flake example uses colmena.lib.makeHive and imports nixpkgs inside meta.nixpkgs.
The replaceUnknownProfiles default is the sharp edge
Colmena's statelessness has a concrete consequence, and the README documents it rather than hiding it. By default, Colmena will replace an unknown remote profile during apply. Unknown means the profile is not present in the Nix store on the machine running Colmena. If several people share a hive, or one person works from multiple machines and does not consistently commit, push and pull, a local apply can overwrite a profile that was built somewhere else. The README's own advice is to set deployment.replaceUnknownProfiles to false in those scenarios, and it can be set per host as well as in defaults.
That is a real failure mode, not a hypothetical one, and it is the cost of keeping no state. A tool that recorded what it last deployed could detect the mismatch. Colmena cannot, because it deliberately does not keep that record. The same property means there is no rollback command in the documented surface. The README does not document rollback. If you need to return a fleet to a previous generation, that is NixOS's own generation mechanism on each host, not something Colmena manages for you.
It is also the wrong tool outside NixOS. Nothing in the README suggests it manages non-NixOS targets, provisions machines, or handles cloud resources. It deploys configurations to hosts that already exist and already run NixOS.
Colmena against deploy-rs
The natural comparison is deploy-rs, another NixOS deployment tool. The architectural difference is where the configuration lives. Colmena's model is a hive: one file, or one flake output, listing every host, with shared defaults and cross-host references through the nodes argument. deploy-rs takes the flake-native route, where each deployable is a nixosConfiguration in flake.nix and deployment parameters live in a deploy block attached to it. If your flake already defines nixosConfigurations for every machine, deploy-rs asks you to add a block to each one. Colmena asks you to assemble a hive, either as a separate hive.nix or as a colmenaHive output.
That difference shows up in selection and in shared configuration. Colmena's tag system, with --on @tag and glob matching, is a first-class way to address a subset of a large fleet from one command, and the defaults module gives every host a shared baseline without repetition. The hive also lets one host read another host's evaluated configuration, which the README's time.timeZone example demonstrates. Neither approach is strictly better; it depends on whether your fleet is described centrally or as a set of independent flake outputs. What is not different is the underlying mechanism: both are thin layers over Nix and SSH, and neither keeps deployment state on your behalf.
Maintenance, licence and what upgrading costs you
The project is not archived, and the last push was on 2026-09-28. The release history is uneven in a way worth knowing before you plan an upgrade: v0.3.2 shipped on 2022-09-29, v0.4.0 on 2023-05-15, and v0.5.0 on 2026-09-22. That is a gap of more than two years between the two most recent minor releases, with the repository's Cargo.toml meanwhile carrying version 0.6.0-pre. A long quiet period followed by a release means you should read the release notes for v0.5.0 rather than assume the upgrade is mechanical, particularly if you pin Colmena in a flake input.
Colmena is MIT licensed. In practical terms that is a permissive licence with no copyleft obligation on your configuration, but it is worth reading the LICENSE file in the repository rather than taking a summary as legal advice.
The maintenance cost of adopting Colmena is mostly the cost of the thing it wraps. You are maintaining a hive.nix or a colmenaHive output, and you are maintaining the Nixpkgs pin inside meta. When Nixpkgs moves, your hive moves with it. Colmena itself is a small dependency, but it is a dependency, and the binary cache at colmena.cachix.org covers unstable builds rather than every version you might pin.
Editorial conclusion
Adopt Colmena if you already run NixOS on the target machines, want a single hive.nix or colmenaHive output to describe them, and are comfortable with a tool that keeps no state and therefore offers no rollback. Do not adopt it if your hosts are not NixOS, if you need a state record of what was deployed when, or if you want the tool to manage the machines themselves rather than their configuration. Before committing, verify two things in your own setup: that you can reach every target as root over SSH, and that deployment.replaceUnknownProfiles is set the way you want, because the README warns that the default can overwrite a remote profile you did not build locally. Then run colmena build before colmena apply, so a build failure never reaches a host.
Frequently asked questions
What is Colmena and what is it for?
It is a stateless NixOS deployment tool written in Rust, modeled after NixOps and morph. It builds a set of NixOS configurations and deploys them to hosts over SSH in parallel, acting as a thin wrapper over Nix commands such as nix-instantiate and nix-copy-closure.
How do I install Colmena?
It is included in Nixpkgs beginning with 21.11, so nix-shell -p colmena gives you the command. For the development version the README gives nix profile add github:nix-community/colmena, and a Cachix binary cache is available at https://colmena.cachix.org.
How does Colmena differ from deploy-rs?
Colmena describes hosts as a hive, either a hive.nix file or an outputs.colmenaHive built with colmena.lib.makeHive, with a defaults module shared by all hosts and tag-based selection through --on @tag. deploy-rs uses per-configuration deploy blocks in a flake. Both are thin layers over Nix and SSH.
Official sources
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.
[](https://hysenlabs.com/projects/nix-community-colmena)