{"article":{"slug":"devenv-2-4-machines","title":"devenv 2.4: Machines","subtitle":null,"summary":"devenv 2.4 adds Machines: declare NixOS (and other) host configs beside your nix-based dev environment, then build, install, and deploy with devenv machines.","content_type":"changelog","language":"en","canonical_url":"https://devenv.sh/blog/2026/09/24/devenv-24-machines/","author":{"name":"devenv team","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"devenv","url":"https://devenv.sh","listing_slug":null,"listing":null},"topics":[{"name":"Developer Tools","slug":"developer-tools","url":"https://listedarticles.com/topics/developer-tools"},{"name":"Open Source","slug":"open-source","url":"https://listedarticles.com/topics/open-source"},{"name":"Infrastructure","slug":"infrastructure","url":"https://listedarticles.com/topics/infrastructure"},{"name":"DevOps","slug":"devops","url":"https://listedarticles.com/topics/devops"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":850,"reading_minutes":4,"published_at":"2026-09-24T00:00:00.000Z","added_at":"2026-09-25T00:13:49.280Z","updated_at":"2026-09-25T00:13:49.280Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/devenv-2-4-machines","markdown_url":"https://listedarticles.com/articles/devenv-2-4-machines.md","example":false,"citation":"devenv team, devenv. \"devenv 2.4: Machines.\" 24 Sept 2026. https://devenv.sh/blog/2026/09/24/devenv-24-machines/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://devenv.sh/blog/2026/09/24/devenv-24-machines/"},"body_markdown":"# devenv 2.4: Machines\n\ndevenv 2.4 introduces Machines.\n\nDefine machine configurations alongside your development environment, then build and deploy them with `devenv machines`.\n\nIt supports:\n\nYou can contribute support for another OS to Machines.\n\nSecretSpec can provide the credentials a new NixOS host needs on its first boot.\n\nMachines are experimental, and we’d like feedback from people using it on real hosts.\n\n## From a development environment to a machine\n\nFor a NixOS server, add the disk and hardware detection inputs:\n\nThen declare the machine in `devenv.nix`:\n\nThe imported NixOS module can define services, users, a bootloader, and a disk layout. devenv wires in disko and nixos-facter. On first install, it saves the host’s hardware report to `.machines/server/facter.json`. Commit that file so others and CI can build the configuration. See the disk layout example before installing.\n\nInspect or build a machine without contacting its target:\n\n`info` lists systems, targets, and roles. `build` realizes all roles for `server` so you can check or cache them before deploying.\n\n## Install a new NixOS host\n\nRun:\n\ndevenv connects over SSH, enters a NixOS installer with kexec, collects hardware facts, and builds the system **before** changing disks. If the build succeeds, it runs disko, installs the system, and reboots.\n\nYou must name each machine. Installation partitions and formats disks without prompting, so check the SSH target and disko disk paths first. Use stable `/dev/disk/by-id/` paths instead of names such as `/dev/sda`. You can install multiple hosts and limit concurrency with `--max-concurrent`.\n\nSee installation options and preflight requirements for encryption keys, extra files, and SSH host key preservation.\n\n## Bootstrap secrets with SecretSpec\n\nA new host may need a secret before sops-nix can start, such as an age identity. Declare it in `secretspec.toml` and map it to a file in the installed system:\n\nIn `./nixos/server.nix`, set `sops.age.keyFile = \"/var/lib/sops-nix/key.txt\";` to use the file on first boot.\n\nWith `execution = \"target\"`, the live installer resolves the secret through its own SecretSpec provider and writes the file after `nixos-install`, before reboot. The workstation sends the declaration, not the secret or provider credentials. The provider must work in the live installer, for example through instance identity. This mode does not require `secretspec.enable` in `devenv.yaml`.\n\nThe default `execution = \"local\"` resolves secrets on your workstation and sends them over SSH. This requires trusting the target’s SSH host key in advance. Neither mode puts secret values in the Nix store. Bootstrap files are written only during `machines install`; use sops-nix or agenix for later rotation. See bootstrapping from SecretSpec for provider setup and transfer details.\n\n## Review a deployment before it changes anything\n\nUse `check` to review SSH access changes without building, or `deploy` to build, review, and apply a NixOS system:\n\n`deploy` compares the build with the running generation and shows closure and access changes. It blocks configurations that disable SSH or root login and warns about changed ports or administrator keys. External firewalls still need your review.\n\nTo review now and deploy later, save a plan:\n\n`apply` uses the planned outputs without rebuilding and rejects a stale plan if the target or NixOS generation has changed. For multiple targets, it prepares all of them before activating any. Both `deploy` and `apply` require confirmation unless you pass `--yes`.\n\n## Recovery runs on the NixOS target\n\nNixOS activation runs in a systemd service on the target, under a deployment lock. A watchdog restores the previous system if activation or a health check fails, or if devenv cannot confirm success before the deadline. It can also recover an unconfirmed deployment after reboot, once NixOS reaches userspace.\n\nConfigure an application health check in `devenv.nix`:\n\nThe default deadline is 300 seconds. Without a custom health check, devenv checks only the system paths. If your connection drops, check the outcome before retrying. Use `rollback` if you need to switch to the previous recorded system:\n\nRecovery requires the target to reach userspace with its previous store paths and state intact. It cannot fix early boot failures or undo application data changes.\n\n## One plan for a mixed fleet\n\nOne machine can combine NixOS or nix-darwin with home-manager. With no machine names, `deploy` selects every SSH target and reviews the fleet together:\n\nEvery role is built, and remote outputs are copied, before activation begins. Machines activate one at a time in name order by default. `--max-concurrent` activates batches; after a failure, no new batches start, but successful machines stay deployed.\n\nWithin a machine, home-manager activates after the system role. NixOS has automatic rollback; nix-darwin and home-manager do not. A failed home-manager activation leaves an already confirmed NixOS deployment in place.\n\nWith the C-Nix backend, `--use-machines-as-builders` makes declared SSH targets available as remote builders for cross-platform deployments.\n\n## Other fixes since 2.3\n\ndevenv 2.3.1 restored public signing key fetching for `cachix.pull` caches and removed duplicate cache entries. This release also fixes quoted `devenv shell` commands, a crash when its terminal closes, and `devenv lsp` startup aborts. See the changelog for the full list.\n\nSee the Machines guide for configuration and operational details.\n\nIf you try Machines, tell us how it goes in a GitHub issue or on Discord.\n\nDomen","body_html":"<h1 id=\"devenv-2-4-machines\">devenv 2.4: Machines</h1>\n<p>devenv 2.4 introduces Machines.</p>\n<p>Define machine configurations alongside your development environment, then build and deploy them with <code>devenv machines</code>.</p>\n<p>It supports:</p>\n<p>You can contribute support for another OS to Machines.</p>\n<p>SecretSpec can provide the credentials a new NixOS host needs on its first boot.</p>\n<p>Machines are experimental, and we’d like feedback from people using it on real hosts.</p>\n<h2 id=\"from-a-development-environment-to-a-machine\">From a development environment to a machine</h2>\n<p>For a NixOS server, add the disk and hardware detection inputs:</p>\n<p>Then declare the machine in <code>devenv.nix</code>:</p>\n<p>The imported NixOS module can define services, users, a bootloader, and a disk layout. devenv wires in disko and nixos-facter. On first install, it saves the host’s hardware report to <code>.machines/server/facter.json</code>. Commit that file so others and CI can build the configuration. See the disk layout example before installing.</p>\n<p>Inspect or build a machine without contacting its target:</p>\n<p><code>info</code> lists systems, targets, and roles. <code>build</code> realizes all roles for <code>server</code> so you can check or cache them before deploying.</p>\n<h2 id=\"install-a-new-nixos-host\">Install a new NixOS host</h2>\n<p>Run:</p>\n<p>devenv connects over SSH, enters a NixOS installer with kexec, collects hardware facts, and builds the system <strong>before</strong> changing disks. If the build succeeds, it runs disko, installs the system, and reboots.</p>\n<p>You must name each machine. Installation partitions and formats disks without prompting, so check the SSH target and disko disk paths first. Use stable <code>/dev/disk/by-id/</code> paths instead of names such as <code>/dev/sda</code>. You can install multiple hosts and limit concurrency with <code>--max-concurrent</code>.</p>\n<p>See installation options and preflight requirements for encryption keys, extra files, and SSH host key preservation.</p>\n<h2 id=\"bootstrap-secrets-with-secretspec\">Bootstrap secrets with SecretSpec</h2>\n<p>A new host may need a secret before sops-nix can start, such as an age identity. Declare it in <code>secretspec.toml</code> and map it to a file in the installed system:</p>\n<p>In <code>./nixos/server.nix</code>, set <code>sops.age.keyFile = &quot;/var/lib/sops-nix/key.txt&quot;;</code> to use the file on first boot.</p>\n<p>With <code>execution = &quot;target&quot;</code>, the live installer resolves the secret through its own SecretSpec provider and writes the file after <code>nixos-install</code>, before reboot. The workstation sends the declaration, not the secret or provider credentials. The provider must work in the live installer, for example through instance identity. This mode does not require <code>secretspec.enable</code> in <code>devenv.yaml</code>.</p>\n<p>The default <code>execution = &quot;local&quot;</code> resolves secrets on your workstation and sends them over SSH. This requires trusting the target’s SSH host key in advance. Neither mode puts secret values in the Nix store. Bootstrap files are written only during <code>machines install</code>; use sops-nix or agenix for later rotation. See bootstrapping from SecretSpec for provider setup and transfer details.</p>\n<h2 id=\"review-a-deployment-before-it-changes-anything\">Review a deployment before it changes anything</h2>\n<p>Use <code>check</code> to review SSH access changes without building, or <code>deploy</code> to build, review, and apply a NixOS system:</p>\n<p><code>deploy</code> compares the build with the running generation and shows closure and access changes. It blocks configurations that disable SSH or root login and warns about changed ports or administrator keys. External firewalls still need your review.</p>\n<p>To review now and deploy later, save a plan:</p>\n<p><code>apply</code> uses the planned outputs without rebuilding and rejects a stale plan if the target or NixOS generation has changed. For multiple targets, it prepares all of them before activating any. Both <code>deploy</code> and <code>apply</code> require confirmation unless you pass <code>--yes</code>.</p>\n<h2 id=\"recovery-runs-on-the-nixos-target\">Recovery runs on the NixOS target</h2>\n<p>NixOS activation runs in a systemd service on the target, under a deployment lock. A watchdog restores the previous system if activation or a health check fails, or if devenv cannot confirm success before the deadline. It can also recover an unconfirmed deployment after reboot, once NixOS reaches userspace.</p>\n<p>Configure an application health check in <code>devenv.nix</code>:</p>\n<p>The default deadline is 300 seconds. Without a custom health check, devenv checks only the system paths. If your connection drops, check the outcome before retrying. Use <code>rollback</code> if you need to switch to the previous recorded system:</p>\n<p>Recovery requires the target to reach userspace with its previous store paths and state intact. It cannot fix early boot failures or undo application data changes.</p>\n<h2 id=\"one-plan-for-a-mixed-fleet\">One plan for a mixed fleet</h2>\n<p>One machine can combine NixOS or nix-darwin with home-manager. With no machine names, <code>deploy</code> selects every SSH target and reviews the fleet together:</p>\n<p>Every role is built, and remote outputs are copied, before activation begins. Machines activate one at a time in name order by default. <code>--max-concurrent</code> activates batches; after a failure, no new batches start, but successful machines stay deployed.</p>\n<p>Within a machine, home-manager activates after the system role. NixOS has automatic rollback; nix-darwin and home-manager do not. A failed home-manager activation leaves an already confirmed NixOS deployment in place.</p>\n<p>With the C-Nix backend, <code>--use-machines-as-builders</code> makes declared SSH targets available as remote builders for cross-platform deployments.</p>\n<h2 id=\"other-fixes-since-2-3\">Other fixes since 2.3</h2>\n<p>devenv 2.3.1 restored public signing key fetching for <code>cachix.pull</code> caches and removed duplicate cache entries. This release also fixes quoted <code>devenv shell</code> commands, a crash when its terminal closes, and <code>devenv lsp</code> startup aborts. See the changelog for the full list.</p>\n<p>See the Machines guide for configuration and operational details.</p>\n<p>If you try Machines, tell us how it goes in a GitHub issue or on Discord.</p>\n<p>Domen</p>","headings":[{"level":1,"text":"devenv 2.4: Machines","id":"devenv-2-4-machines"},{"level":2,"text":"From a development environment to a machine","id":"from-a-development-environment-to-a-machine"},{"level":2,"text":"Install a new NixOS host","id":"install-a-new-nixos-host"},{"level":2,"text":"Bootstrap secrets with SecretSpec","id":"bootstrap-secrets-with-secretspec"},{"level":2,"text":"Review a deployment before it changes anything","id":"review-a-deployment-before-it-changes-anything"},{"level":2,"text":"Recovery runs on the NixOS target","id":"recovery-runs-on-the-nixos-target"},{"level":2,"text":"One plan for a mixed fleet","id":"one-plan-for-a-mixed-fleet"},{"level":2,"text":"Other fixes since 2.3","id":"other-fixes-since-2-3"}]}}