<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fh="http://purl.org/syndication/history/1.0"><channel><title>devenv | Blog</title><description/><link>https://devenv.sh/</link><language>en</language><atom:link rel="self" href="https://devenv.sh/blog/rss.xml"/><atom:link rel="prev-archive" href="https://devenv.sh/blog/rss/2026-07.xml"/><item><title>devenv 2.2: attach to running processes and persistent out-of-tree environments</title><link>https://devenv.sh/blog/2026/07/28/devenv-22-attach-to-running-processes-and-persistent-out-of-tree-environments/</link><guid isPermaLink="true">https://devenv.sh/blog/2026/07/28/devenv-22-attach-to-running-processes-and-persistent-out-of-tree-environments/</guid><pubDate>Tue, 28 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/releases#release-v2.2&quot;&gt;devenv 2.2&lt;/a&gt; ships:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#one-process-manager-many-terminals&quot;&gt;Attach to running processes&lt;/a&gt;:&lt;/strong&gt; share one native process manager across terminals, with live status, ports, logs, and a choice to detach or stop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#configure-an-environment-once-use-it-anywhere&quot;&gt;Persistent out-of-tree environments&lt;/a&gt;:&lt;/strong&gt; bind a directory to a local or remote &lt;code dir=&quot;auto&quot;&gt;--from&lt;/code&gt; source, including profiles and the source’s complete &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#shell-activation-gets-out-of-the-way&quot;&gt;More reliable shell activation&lt;/a&gt;:&lt;/strong&gt; automatically load hooks in fish and nushell, select the correct login shell in stripped environments, and behave predictably in multiplexers and nested shells.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#secretspec-017-and-cachix-integration&quot;&gt;SecretSpec 0.17 and Cachix integration&lt;/a&gt;:&lt;/strong&gt; upgrade from SecretSpec 0.8, pull and push to private caches without exporting &lt;code dir=&quot;auto&quot;&gt;CACHIX_AUTH_TOKEN&lt;/code&gt;, and run the bundled SecretSpec CLI with the same profile and provider as devenv.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#tui-calmer-sturdier&quot;&gt;A calmer and sturdier TUI&lt;/a&gt;:&lt;/strong&gt; use near-zero CPU while idle, distinguish every process state at a glance, and handle unusual terminal input safely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#evaluation-cache-fixes&quot;&gt;Evaluation cache fixes&lt;/a&gt;:&lt;/strong&gt; invalidate correctly when local inputs, copied sources, and files modified during evaluation change.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#for-automation-and-coding-agents&quot;&gt;Better automation interfaces&lt;/a&gt;:&lt;/strong&gt; inspect tasks as JSON, access inputs in the REPL, distinguish trace callers, and avoid streaming interactive output into coding agents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;#smaller-installs-and-better-diagnostics&quot;&gt;Smaller installs and better diagnostics&lt;/a&gt;:&lt;/strong&gt; remove unnecessary LLVM and debug-toolchain dependencies while surfacing clearer errors in terminals and CI.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;one-process-manager-many-terminals&quot;&gt;One process manager, many terminals&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Running &lt;code dir=&quot;auto&quot;&gt;devenv up&lt;/code&gt; while the native process manager is already active now &lt;strong&gt;attaches&lt;/strong&gt; to it instead of failing (&lt;a href=&quot;https://github.com/cachix/devenv/pull/2936&quot;&gt;devenv#2936&lt;/a&gt;). The second invocation connects over the control socket, starts any requested processes that aren’t running yet, and streams status, ports, and logs.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;up&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-d&lt;/span&gt;&lt;span&gt;                      &lt;/span&gt;&lt;span&gt;# start processes in the background&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;up&lt;/span&gt;&lt;span&gt;                         &lt;/span&gt;&lt;span&gt;# attach: live status, ports, and logs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;attach&lt;/span&gt;&lt;span&gt;           &lt;/span&gt;&lt;span&gt;# watch without requesting any starts&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;postgres&lt;/span&gt;&lt;span&gt;   &lt;/span&gt;&lt;span&gt;# start one process, cold-starting a manager if needed&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The manager resolves &lt;code dir=&quot;auto&quot;&gt;before&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;after&lt;/code&gt; ordering through its own task scheduler. An attached terminal first receives the current state and recent log output, then follows live changes. Other terminals can attach and detach independently without taking ownership away from the daemon.&lt;/p&gt;
&lt;p&gt;Ctrl-C on an attached &lt;code dir=&quot;auto&quot;&gt;devenv up&lt;/code&gt; asks whether you want to detach and leave the processes running, or stop the whole manager. &lt;code dir=&quot;auto&quot;&gt;devenv processes attach&lt;/code&gt; always detaches on Ctrl-C.&lt;/p&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;devenv processes start &amp;#x3C;name&gt;&lt;/code&gt; no longer requires a manager to be running. It can cold-start one in the background with that process and its dependency closure, equivalent to &lt;code dir=&quot;auto&quot;&gt;devenv up -d &amp;#x3C;name&gt;&lt;/code&gt; (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2930&quot;&gt;devenv#2930&lt;/a&gt;). Named starts always start the requested process, even when its default &lt;code dir=&quot;auto&quot;&gt;start.enable&lt;/code&gt; is false.&lt;/p&gt;
&lt;p&gt;Attaching is deliberately interactive. CI jobs, piped commands, and detected coding agents report that processes are already running instead of entering a live view that could wait indefinitely.&lt;/p&gt;
&lt;p&gt;Under the hood, the process manager became the single owner of process state, the daemon pushes attach sessions as an event stream instead of being polled, and every process launch goes through the same task graph. This fixed a family of lifecycle bugs along the way: double launches, processes vanishing from &lt;code dir=&quot;auto&quot;&gt;list&lt;/code&gt;, stuck relaunches, concurrent daemon startup, and a foreground &lt;code dir=&quot;auto&quot;&gt;devenv up&lt;/code&gt; corrupting a running daemon’s PID file.&lt;/p&gt;
&lt;p&gt;Closes &lt;a href=&quot;https://github.com/cachix/devenv/issues/971&quot;&gt;devenv#971&lt;/a&gt;, open since February 2024.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;configure-an-environment-once-use-it-anywhere&quot;&gt;Configure an environment once, use it anywhere&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://devenv.sh/ad-hoc-developer-environments/&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;--from&lt;/code&gt;&lt;/a&gt; lets you use a devenv without checking &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; into the project. In 2.1 you had to repeat the flag for every command. In 2.2, &lt;code dir=&quot;auto&quot;&gt;devenv allow&lt;/code&gt; can bind the current directory to that source:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;my-project&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;github:myorg/devenv-configs?dir=rust-web&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;allow&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Every subsequent devenv command in that directory loads the bound configuration. The native shell hook auto activates it on &lt;code dir=&quot;auto&quot;&gt;cd&lt;/code&gt;, just like a project with a local &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Profiles persist with the binding:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;github:myorg/devenv-configs&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;--profile&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;backend&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;--profile&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;observability&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;allow&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;An explicit &lt;code dir=&quot;auto&quot;&gt;--profile&lt;/code&gt; still takes priority when you need a one-off override.&lt;/p&gt;
&lt;p&gt;Local sources now bring their entire configuration with them. &lt;code dir=&quot;auto&quot;&gt;--from path:../shared-devenv&lt;/code&gt; loads the source’s &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt;, inputs, imports, and sibling modules from its Git repository. Modules are read from the live directory, so edits take effect without fetching or rebinding the source.&lt;/p&gt;
&lt;p&gt;Normal in-tree projects are easier to navigate too: devenv now walks up parent directories to find &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt;. Commands work from any subdirectory while the shell and &lt;code dir=&quot;auto&quot;&gt;devenv shell -- &amp;#x3C;command&gt;&lt;/code&gt; keep the directory where you invoked them (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2232&quot;&gt;devenv#2232&lt;/a&gt;).&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;shell-activation-gets-out-of-the-way&quot;&gt;Shell activation gets out of the way&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The native shell integration added in 2.1 now loads automatically in fish and nushell through their vendor configuration mechanisms. Bash and zsh have no equivalent, so they still need the one-line &lt;a href=&quot;https://devenv.sh/auto-activation/&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;devenv hook&lt;/code&gt;&lt;/a&gt; setup in your shell configuration.&lt;/p&gt;
&lt;p&gt;Shell selection is more reliable in editor terminals and stripped environments where &lt;code dir=&quot;auto&quot;&gt;$SHELL&lt;/code&gt; is missing. devenv looks up the user’s login shell before falling back to bash, and warns when a shell explicitly requested through &lt;code dir=&quot;auto&quot;&gt;--shell&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt; is unsupported (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2880&quot;&gt;devenv#2880&lt;/a&gt;, &lt;a href=&quot;https://github.com/cachix/devenv/pull/2992&quot;&gt;devenv#2992&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Activation and deactivation have also been hardened across real-world shell setups:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New tmux and zellij panes, SSH sessions, and nested shells no longer inherit a marker that can close them when they change directory (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2861&quot;&gt;devenv#2861&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Leaving and immediately re-entering a project activates it again on the first try.&lt;/li&gt;
&lt;li&gt;Fish preserves &lt;code dir=&quot;auto&quot;&gt;cd -&lt;/code&gt; history and works when zoxide overrides &lt;code dir=&quot;auto&quot;&gt;cd&lt;/code&gt; (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2853&quot;&gt;devenv#2853&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;A manually entered &lt;code dir=&quot;auto&quot;&gt;devenv shell&lt;/code&gt;, or an environment already loaded by direnv, no longer gets another devenv shell stacked on top.&lt;/li&gt;
&lt;li&gt;Nushell now deactivates reliably when leaving a project.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you still use direnv, &lt;code dir=&quot;auto&quot;&gt;devenv init --include-envrc&lt;/code&gt; (or &lt;code dir=&quot;auto&quot;&gt;DEVENV_INCLUDE_ENVRC&lt;/code&gt;) adds an &lt;code dir=&quot;auto&quot;&gt;.envrc&lt;/code&gt; to a new project. Native activation remains the default and requires no project-local activation file.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;secretspec-017-and-cachix-integration&quot;&gt;SecretSpec 0.17 and Cachix integration&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;devenv 2.2 upgrades its SecretSpec integration from 0.8 to &lt;a href=&quot;https://secretspec.dev/blog/secretspec-0-17-scopes-secrets-caching-age-and-systemd-credentials/&quot;&gt;SecretSpec 0.17&lt;/a&gt;. The release adds scopes, secrets caching, cross-secret validation, GitHub and Forgejo Actions support, and new providers including SOPS, age, KeePass KDBX, OpenBao, Scaleway Secret Manager, and systemd credentials.&lt;/p&gt;
&lt;p&gt;Pulling from and pushing to private Cachix caches no longer requires exporting &lt;code dir=&quot;auto&quot;&gt;CACHIX_AUTH_TOKEN&lt;/code&gt;. devenv can resolve the token through &lt;a href=&quot;https://secretspec.dev&quot;&gt;SecretSpec&lt;/a&gt; without exposing it to the development shell:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;provider&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;keyring&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;cachix_auth_token&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;No declaration in &lt;code dir=&quot;auto&quot;&gt;secretspec.toml&lt;/code&gt; is required. If SecretSpec does not return a token, devenv falls back to the token stored by the Cachix CLI through &lt;code dir=&quot;auto&quot;&gt;cachix authtoken&lt;/code&gt;. The resolved token is used for both pulls and the Cachix push daemon.&lt;/p&gt;
&lt;p&gt;If your secrets backend grants access to the token under a different name, configure it in &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;cachix_auth_token&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;CI_CACHIX_TOKEN&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The string is the secret’s name, not the token itself.&lt;/p&gt;
&lt;p&gt;The matching &lt;code dir=&quot;auto&quot;&gt;secretspec&lt;/code&gt; command is now bundled with devenv. The profile and provider selected in &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt; are exported as &lt;code dir=&quot;auto&quot;&gt;SECRETSPEC_PROFILE&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;SECRETSPEC_PROVIDER&lt;/code&gt;, so runtime commands use the same configuration that devenv used during evaluation:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;npm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;tui-calmer-sturdier&quot;&gt;TUI: calmer, sturdier&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Process status at a glance.&lt;/strong&gt; Each process now shows a status dot whose shape encodes its lifecycle instead of an identical spinner on every row. Waiting, starting, running, ready, stopped, exited, failed, and gave-up states remain distinct. The shape carries the state, so it reads without relying on color.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Near zero idle CPU.&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;devenv up&lt;/code&gt; was burning roughly 10 to 15% CPU per managed process even when everything was quiet, because the UI recomputed its layout dozens of times per second. The TUI now only redraws when something actually changes (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2915&quot;&gt;devenv#2915&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fuzzed nightly.&lt;/strong&gt; The TUI gained property-based tests and a nightly terminal fuzzing run, which already flushed out crashes on multi-byte characters, progress overflow, and narrow terminals.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better terminal rendering.&lt;/strong&gt; Long structured logs and stack traces wrap instead of being truncated. Shell output is read in larger batches, reducing rendering overhead, and long lines copied from &lt;code dir=&quot;auto&quot;&gt;devenv shell&lt;/code&gt; no longer acquire a hard newline at the terminal’s wrap point (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2865&quot;&gt;devenv#2865&lt;/a&gt;).&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;evaluation-cache-fixes&quot;&gt;Evaluation cache fixes&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Local &lt;code dir=&quot;auto&quot;&gt;path:&lt;/code&gt; inputs now participate in cache invalidation. Editing a shared configuration applies on the next command instead of returning stale results until &lt;code dir=&quot;auto&quot;&gt;.devenv&lt;/code&gt; is deleted.&lt;/p&gt;
&lt;p&gt;The cache also tracks local files and directories copied into the Nix store during evaluation. Directories are hashed recursively, so changes to nested scripts and imported source trees invalidate the attributes that depend on them (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2886&quot;&gt;devenv#2886&lt;/a&gt;, &lt;a href=&quot;https://github.com/cachix/devenv/issues/2893&quot;&gt;devenv#2893&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;If a tracked file changes while an evaluation is still running, that result is no longer stored. This closes a race where editing &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; at the wrong moment could leave stale tasks or options behind (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2745&quot;&gt;devenv#2745&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Other fixes cover newly created files with sub-second timestamps, SQLite caches on VM-mounted filesystems, and shells built through relocated or chrooted Nix stores (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2499&quot;&gt;devenv#2499&lt;/a&gt;, &lt;a href=&quot;https://github.com/cachix/devenv/issues/2947&quot;&gt;devenv#2947&lt;/a&gt;).&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;for-automation-and-coding-agents&quot;&gt;For automation and coding agents&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;devenv down&lt;/code&gt;.&lt;/strong&gt; A shorthand for &lt;code dir=&quot;auto&quot;&gt;devenv processes down&lt;/code&gt;, mirroring &lt;code dir=&quot;auto&quot;&gt;devenv up&lt;/code&gt; (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2862&quot;&gt;devenv#2862&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;devenv tasks list --json&lt;/code&gt;.&lt;/strong&gt; Machine readable task graph inspection (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2966&quot;&gt;devenv#2966&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;inputs&lt;/code&gt; in the REPL.&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;devenv repl&lt;/code&gt; now exposes &lt;code dir=&quot;auto&quot;&gt;inputs&lt;/code&gt; alongside &lt;code dir=&quot;auto&quot;&gt;devenv&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;pkgs&lt;/code&gt;, so you can poke at inputs declared in &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt; directly (e.g. &lt;code dir=&quot;auto&quot;&gt;inputs.nixpkgs.lib.version&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Better agent detection.&lt;/strong&gt; Quiet mode now kicks in for more coding agents (Aider, autonomous and cloud agents, and others) via the &lt;code dir=&quot;auto&quot;&gt;detect-coding-agent&lt;/code&gt; crate, not just Claude Code. Set &lt;code dir=&quot;auto&quot;&gt;DEVENV_NO_AI_AGENT=1&lt;/code&gt; to opt out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trace callers.&lt;/strong&gt; OpenTelemetry spans now identify whether devenv was invoked by the CLI, direnv, or the native shell hook through the &lt;code dir=&quot;auto&quot;&gt;devenv.caller&lt;/code&gt; attribute (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2965&quot;&gt;devenv#2965&lt;/a&gt;). &lt;code dir=&quot;auto&quot;&gt;DEVENV_TRACE_DEFAULT_TO&lt;/code&gt; configures a default trace destination without overriding an explicit &lt;code dir=&quot;auto&quot;&gt;--trace-to&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;DEVENV_TRACE_TO&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;smaller-installs-and-better-diagnostics&quot;&gt;Smaller installs and better diagnostics&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Statically linking &lt;code dir=&quot;auto&quot;&gt;nixd&lt;/code&gt;, used by &lt;code dir=&quot;auto&quot;&gt;devenv lsp&lt;/code&gt;, removes the monolithic LLVM shared library and reduces the devenv closure and container image by roughly 550 MiB. Building libghostty-vt in release mode also avoids pulling a debug toolchain containing Zig and LLVM into every installation.&lt;/p&gt;
&lt;p&gt;Non-TUI output now shows useful Nix evaluation and build progress while hiding internal debug noise. Evaluation warnings no longer replace the real error message, &lt;code dir=&quot;auto&quot;&gt;devenv test --no-tui&lt;/code&gt; preserves test output in CI, and unfree-package errors point to the relevant devenv configuration instead of generic NixOS advice.&lt;/p&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;devenv shell&lt;/code&gt; also terminates its inner shell when the terminal closes instead of leaving a background process at 100% CPU (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2845&quot;&gt;devenv#2845&lt;/a&gt;). GitHub inputs resolve over SSH when a &lt;code dir=&quot;auto&quot;&gt;url.insteadOf&lt;/code&gt; rule rewrites them, using your SSH agent (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2842&quot;&gt;devenv#2842&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;See the full &lt;a href=&quot;https://github.com/cachix/devenv/blob/main/CHANGELOG.md&quot;&gt;changelog&lt;/a&gt; for the rest.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dropped &lt;code dir=&quot;auto&quot;&gt;x86_64-darwin&lt;/code&gt; (Intel macOS).&lt;/strong&gt; devenv is no longer built, tested, or released for Intel Macs. Pin an older devenv release if you’re on one. &lt;code dir=&quot;auto&quot;&gt;x86_64-darwin&lt;/code&gt; environments still run through Rosetta 2 on Apple Silicon, though nixpkgs 26.05 will be its final supported nixpkgs release.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto activation detects &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt;.&lt;/strong&gt; The shell hook and &lt;code dir=&quot;auto&quot;&gt;devenv allow&lt;/code&gt; now look for &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; instead of &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt;. Projects with only a &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt; no longer auto activate; add a &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; to restore activation.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;final-words&quot;&gt;Final words&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/issues&quot;&gt;Open an issue&lt;/a&gt; or join the &lt;a href=&quot;https://discord.gg/naMgvexb6q&quot;&gt;Discord&lt;/a&gt; with feedback.&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>Making devenv start fast, and the whole nixpkgs with it</title><link>https://devenv.sh/blog/2026/06/26/making-devenv-start-fast-and-the-whole-nixpkgs-with-it/</link><guid isPermaLink="true">https://devenv.sh/blog/2026/06/26/making-devenv-start-fast-and-the-whole-nixpkgs-with-it/</guid><pubDate>Fri, 26 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m sitting here next to &lt;a href=&quot;https://github.com/fzakaria&quot;&gt;Farid Zakaria&lt;/a&gt; at &lt;a href=&quot;https://tacosprint.org&quot;&gt;Tacosprint&lt;/a&gt; where we looked at the stat storm that has been haunting nixpkgs for a decade.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://devenv.sh/assets/images/tacosprint.webp&quot; alt=&quot;The Tacosprint table&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devenv.sh/auto-activation/&quot;&gt;devenv auto activation&lt;/a&gt; runs &lt;code dir=&quot;auto&quot;&gt;devenv hook-should-activate&lt;/code&gt; on every shell prompt to decide whether you’ve stepped
into a project directory. It does almost nothing: discover the project, check
the trust database, print a path. So its runtime is pure startup overhead, and
it runs on every single prompt redraw.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$ &lt;/span&gt;&lt;span&gt;time&lt;/span&gt;&lt;span&gt; devenv hook-should-activate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/home/domen/dev/myproject&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;real    0m0.070s&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;70ms before a prompt, every prompt.&lt;/p&gt;
&lt;p&gt;And this isn’t devenv’s tax to pay, it’s nixpkgs’. Every program pays it before
it runs a line of its own code: the dynamic loader has to find each shared
library, and the way Nix scatters packages across the store makes that search
slow. This is not news. The cost has been measured, written up, and partly fixed
more than once, and yet it has sat in limbo for the better part of a decade with
no general fix merged into nixpkgs.&lt;/p&gt;
&lt;p&gt;Most of that is the dynamic loader looking for a shared object that is sitting
right there in the store, just not in the first directory it tried. The loader
knocks on 486 wrong doors before it finds the right ones, and almost all of it
happens before &lt;code dir=&quot;auto&quot;&gt;main&lt;/code&gt; even starts.&lt;/p&gt;
&lt;p&gt;That number is the whole game. Above ~30ms you have to bolt a caching layer on
top of the hook; in single digit milliseconds you just run it on every prompt
and throw the cache away.&lt;/p&gt;
&lt;p&gt;And it scales with the closure: &lt;code dir=&quot;auto&quot;&gt;imagemagick&lt;/code&gt;’s &lt;code dir=&quot;auto&quot;&gt;magick --version&lt;/code&gt;
makes &lt;strong&gt;1225&lt;/strong&gt; failing opens:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$ strace -f -e openat magick --version &lt;/span&gt;&lt;span&gt;2&gt;&amp;#x26;1&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt;/dev/null &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;\.so&apos;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;grep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-c&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;ENOENT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;1225&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The community has been circling a real fix for years. This post walks through
the problem, the approaches people have tried with their tradeoffs, and a more
radical one we spiked for devenv to see if it was even possible: deleting the
dynamic loader altogether by linking the whole program into one static binary.&lt;/p&gt;
&lt;p&gt;The umbrella tracking issue for the general problem is
&lt;a href=&quot;https://github.com/NixOS/nixpkgs/issues/481620&quot;&gt;NixOS/nixpkgs#481620&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;why-nix-makes-the-loader-work-so-hard&quot;&gt;Why Nix makes the loader work so hard&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;On a traditional distribution every shared library lives in a handful of global
directories such as &lt;code dir=&quot;auto&quot;&gt;/usr/lib&lt;/code&gt;. The dynamic loader has a short, mostly cached
search path, and &lt;code dir=&quot;auto&quot;&gt;ld.so.cache&lt;/code&gt; (built by &lt;code dir=&quot;auto&quot;&gt;ldconfig&lt;/code&gt;) turns soname lookups into a
hash table hit.&lt;/p&gt;
&lt;p&gt;Nix is different by design. Every package lives in its own
&lt;code dir=&quot;auto&quot;&gt;/nix/store/&amp;#x3C;hash&gt;-name/lib&lt;/code&gt; directory, and there is no global &lt;code dir=&quot;auto&quot;&gt;ld.so.cache&lt;/code&gt; for
store libraries. To make a binary find its dependencies, Nix records a
&lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt; in the ELF header that lists &lt;strong&gt;one directory per dependency&lt;/strong&gt;. A
program linked against fifty libraries gets a &lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt; with dozens of
entries.&lt;/p&gt;
&lt;p&gt;Now recall how glibc resolves a &lt;code dir=&quot;auto&quot;&gt;DT_NEEDED&lt;/code&gt; soname with &lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt; present: it
walks every &lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt; directory in order, trying to open &lt;code dir=&quot;auto&quot;&gt;dir/soname&lt;/code&gt; in
each, until one succeeds. So resolving N libraries against a path of M
directories costs on the order of N times M &lt;code dir=&quot;auto&quot;&gt;openat()&lt;/code&gt; attempts, almost all of
which fail. That is the stat storm.&lt;/p&gt;
&lt;p&gt;It gets worse. For every directory it searches, glibc first probes the
&lt;code dir=&quot;auto&quot;&gt;glibc-hwcaps&lt;/code&gt; subdirectories for your CPU (&lt;code dir=&quot;auto&quot;&gt;x86-64-v3&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;x86-64-v2&lt;/code&gt;, and so on),
which adds roughly three more failing opens per directory on a modern machine.
On a fast SSD with a warm cache none of this is noticeable. On a slow disk, a
network filesystem, a cold cache, or a low power ARM board, it is the difference
between snappy and sluggish, and it multiplies across every process a shell
script spawns.&lt;/p&gt;
&lt;p&gt;Concretely, the two workloads we traced most closely:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workload&lt;/th&gt;
&lt;th&gt;Loaded libraries&lt;/th&gt;
&lt;th&gt;&lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt; dirs&lt;/th&gt;
&lt;th&gt;Failing &lt;code dir=&quot;auto&quot;&gt;.so&lt;/code&gt; opens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;devenv version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;83&lt;/td&gt;
&lt;td&gt;12 (leaf binary)&lt;/td&gt;
&lt;td&gt;~486&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;imagemagick magick --version&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;91&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;td&gt;~1225&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The wider a binary’s own &lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt; and the deeper its transitive graph, the
worse the storm.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-a-good-fix-has-to-preserve&quot;&gt;What a good fix has to preserve&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The reason this problem has stayed open so long is that the obvious fixes break
things people rely on. Any serious solution is judged against a checklist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt; override.&lt;/strong&gt; NixOS injects the GPU driver by putting
&lt;code dir=&quot;auto&quot;&gt;/run/opengl-driver/lib&lt;/code&gt; on &lt;code dir=&quot;auto&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt;. If a fix stops that from
winning, graphics break.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;LD_PRELOAD&lt;/code&gt;.&lt;/strong&gt; Interposers and shims must still load first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The libGL / glvnd runtime swap.&lt;/strong&gt; A program built against Mesa must be able
to pick up the vendor driver at runtime.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Two libraries with the same soname.&lt;/strong&gt; This is the heart of the Nix model:
different parts of one closure can legitimately depend on different builds of
the same soname, and resolution must stay per object.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;dlopen&lt;/code&gt;.&lt;/strong&gt; Plugins loaded at runtime are a related but separate problem.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross compilation.&lt;/strong&gt; A fix that has to run the target loader cannot cross
compile cleanly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disk and closure size.&lt;/strong&gt; Whatever metadata you add ships in every NAR.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maintenance burden.&lt;/strong&gt; A glibc or loader patch has to be rebased onto
every new glibc release, and patching glibc rebuilds the world.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;No approach so far ticks every box. The interesting part is how each one chooses
which boxes to give up.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;approach-1-freeze-the-resolution-with-absolute-paths&quot;&gt;Approach 1: freeze the resolution with absolute paths&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The simplest idea: rewrite every &lt;code dir=&quot;auto&quot;&gt;DT_NEEDED&lt;/code&gt; entry from a bare soname like
&lt;code dir=&quot;auto&quot;&gt;libfoo.so.1&lt;/code&gt; to the absolute store path of the library it resolves to. glibc
has a “slash short circuit”: a &lt;code dir=&quot;auto&quot;&gt;DT_NEEDED&lt;/code&gt; containing a &lt;code dir=&quot;auto&quot;&gt;/&lt;/code&gt; is opened directly,
skipping all search. No search means no storm, and not even the &lt;code dir=&quot;auto&quot;&gt;glibc-hwcaps&lt;/code&gt;
probes happen.&lt;/p&gt;
&lt;p&gt;This is well trodden ground:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/fzakaria&quot;&gt;Farid Zakaria&lt;/a&gt;’s &lt;strong&gt;shrinkwrap&lt;/strong&gt; and the
&lt;strong&gt;nix-harden-needed&lt;/strong&gt; tool do exactly
this as external post processing. Shrinkwrap is described in the paper
&lt;a href=&quot;https://ar5iv.labs.arxiv.org/html/2211.05118&quot;&gt;&lt;em&gt;Mapping Out the HPC Dependency Chaos&lt;/em&gt;&lt;/a&gt;
(Zakaria, Scogland, Gamblin, Maltzahn, 2022; arXiv:2211.05118), which measures
the storm directly: an Emacs launch drops from 1823 &lt;code dir=&quot;auto&quot;&gt;stat&lt;/code&gt;/&lt;code dir=&quot;auto&quot;&gt;openat&lt;/code&gt; syscalls
to 104, a 36 times speedup, and a 900 library MPI application starting across
2048 processes on NFS goes from 344.6s to 47.8s, 7.2 times faster. Those NFS
numbers are the clearest evidence that this overhead, invisible on a warm
local cache, becomes brutal on a network or cold filesystem.&lt;/li&gt;
&lt;li&gt;patchelf &lt;a href=&quot;https://github.com/NixOS/patchelf/pull/357&quot;&gt;PR #357&lt;/a&gt;
(&lt;code dir=&quot;auto&quot;&gt;--shrink-wrap&lt;/code&gt;, open since 2021) pulls all transitive &lt;code dir=&quot;auto&quot;&gt;DT_NEEDED&lt;/code&gt; up onto
the top binary and rewrites them to absolute paths.&lt;/li&gt;
&lt;li&gt;Spack has a similar &lt;code dir=&quot;auto&quot;&gt;bind&lt;/code&gt; feature in the HPC world.&lt;/li&gt;
&lt;li&gt;Inside nixpkgs, this mechanism is already used ad hoc in dozens of packages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The cost is steep on the checklist. Absolute paths &lt;strong&gt;lose the &lt;code dir=&quot;auto&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt;
override&lt;/strong&gt;, so the glvnd driver swap stops working, and you need an exemption
list for libc, the loader itself, the GL stack, and initrd. There is also no
runtime fallback: if the pinned path is gone, the program does not start.&lt;/p&gt;
&lt;p&gt;There is also a build time fork in the road here. To rewrite a soname to an
absolute path you first have to resolve it, and there are two ways to do that:
&lt;strong&gt;run the binary’s own loader&lt;/strong&gt; and record what glibc actually picks, or walk
&lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt; statically and resolve it yourself. The first is exact but executes
target code, so it cannot cross compile; the second cross compiles cleanly. The
absolute path tooling only ever did the first, which is why it stays a manual,
per package tool rather than a default. The static walk is the same technique
the ELF note cache (approach 3) later builds on.&lt;/p&gt;
&lt;p&gt;So absolute paths are the zero disk, maximum speed option, attractive for self
contained leaf applications, but wrong as a default because of the override
semantics.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;approach-2-the-runpath-symlink-farm&quot;&gt;Approach 2: the RUNPATH symlink farm&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;If the problem is that the loader searches many directories, give it one. The
farm idea, floated early on by &lt;a href=&quot;https://github.com/lheckemann&quot;&gt;Linus Heckemann&lt;/a&gt;
(see &lt;a href=&quot;https://github.com/NixOS/nixpkgs/pull/24844&quot;&gt;#24844&lt;/a&gt;), is: for each ELF,
create
a single directory of symlinks pointing at exactly the libraries that ELF needs,
and set its &lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt; to that one directory.&lt;/p&gt;
&lt;p&gt;The crucial detail is that the sonames in &lt;code dir=&quot;auto&quot;&gt;DT_NEEDED&lt;/code&gt; stay short. The farm only
changes where they are found, not how. Because the farm lives in &lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt;,
which the loader consults after &lt;code dir=&quot;auto&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt;, every override keeps working.
And it builds with nothing but stock &lt;code dir=&quot;auto&quot;&gt;patchelf --set-rpath&lt;/code&gt; and symlinks, with
no glibc or patchelf fork, and never executes the target binary, so it cross
compiles.&lt;/p&gt;
&lt;p&gt;But keeping the sonames short is also where it breaks the Nix model. A farm
directory is a flat namespace keyed by soname, so it can hold exactly one
&lt;code dir=&quot;auto&quot;&gt;libfoo.so.1&lt;/code&gt;. When a closure legitimately pulls two different builds of the
same soname (the case Nix exists to allow), the farm cannot represent both, and
glibc’s soname based dedup collapses them to whichever loads first. Absolute
paths (approach 1) sidestep this because the store path becomes the key; the
farm, which deliberately keeps the bare soname, cannot.&lt;/p&gt;
&lt;p&gt;The remaining costs are store pollution and the hwcaps floor. Every ELF gains
its own extra directory of symlinks, so the store fills up with farm directories
that shadow the real libraries. And the farm collapses the per directory
multiplier but &lt;strong&gt;not&lt;/strong&gt; the per hwcaps multiplier: the loader still probes
&lt;code dir=&quot;auto&quot;&gt;glibc-hwcaps&lt;/code&gt; inside the one farm directory. So it is a large constant factor
win, not an asymptotic one.&lt;/p&gt;
&lt;p&gt;How large depends entirely on how much of the graph you farm:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Farmed scope&lt;/th&gt;
&lt;th&gt;Failing opens&lt;/th&gt;
&lt;th&gt;Reduction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;imagemagick&lt;/code&gt;, binary only (wide 35 dir &lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;1225 → ~213&lt;/td&gt;
&lt;td&gt;83%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;devenv&lt;/code&gt;, leaf binary only (narrow 12 dir &lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;486 → 392&lt;/td&gt;
&lt;td&gt;19%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;devenv&lt;/code&gt;, whole graph (every dep built with the hook)&lt;/td&gt;
&lt;td&gt;486 → 88&lt;/td&gt;
&lt;td&gt;82%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The two devenv rows are the lesson. Farming the leaf alone barely moves the
needle because the storm there is dominated by the 83 libraries resolving &lt;em&gt;each
other&lt;/em&gt;, which a leaf only farm never touches. Only whole graph adoption reaches
82%, and the residual 88 are irreducible hwcaps probes rather than real library
searches. So the farm pays off immediately when a package’s own binary has a
wide &lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt;, but needs whole graph adoption for closure heavy
applications.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;approach-3-a-per-dso-resolution-cache-in-an-elf-note&quot;&gt;Approach 3: a per DSO resolution cache in an ELF note&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;This is the most ambitious approach and, on the checklist, the best. The idea,
designed by &lt;a href=&quot;https://github.com/pennae&quot;&gt;pennae&lt;/a&gt; in
&lt;a href=&quot;https://github.com/NixOS/nixpkgs/pull/207893&quot;&gt;#207893&lt;/a&gt;: have &lt;code dir=&quot;auto&quot;&gt;patchelf&lt;/code&gt; write a
small &lt;code dir=&quot;auto&quot;&gt;PT_NOTE&lt;/code&gt; into each library that records, for each &lt;code dir=&quot;auto&quot;&gt;DT_NEEDED&lt;/code&gt; soname,
where the loader should find it. A patched glibc reads that note during loading,
between the &lt;code dir=&quot;auto&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt; step and the &lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt; walk, and resolves the
dependency straight from it.&lt;/p&gt;
&lt;p&gt;Placing the read after &lt;code dir=&quot;auto&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt; is what makes it safe: overrides,
&lt;code dir=&quot;auto&quot;&gt;LD_PRELOAD&lt;/code&gt;, and the glvnd swap all keep winning, and soname based dedup is
unchanged because the sonames stay short. Each cache entry is either an exact
path, which is opened directly with no search and therefore no hwcaps probing,
or a directory hint for the rare cases that cannot be resolved at build time
(&lt;code dir=&quot;auto&quot;&gt;$ORIGIN&lt;/code&gt; relative entries, or directories that themselves contain a
&lt;code dir=&quot;auto&quot;&gt;glibc-hwcaps&lt;/code&gt; tree).&lt;/p&gt;
&lt;p&gt;This is the only approach that preserves every semantic, adds zero closure
references, and eliminates the hwcaps floor as well. pennae’s original benchmark
showed an armv7 workload dropping from 44s to 29s (seconds, not ms, measured
under &lt;code dir=&quot;auto&quot;&gt;strace -cf&lt;/code&gt;) with about 24000 fewer syscalls. In our own end to end test of a revived, cleaned up version, a note
bearing binary resolved its dependency with &lt;strong&gt;zero&lt;/strong&gt; failing search probes,
versus the full storm for the same binary without the note, while the
&lt;code dir=&quot;auto&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt; override still took precedence.&lt;/p&gt;
&lt;p&gt;The price is the heaviest of any approach. It needs &lt;strong&gt;two&lt;/strong&gt; source changes: a
glibc patch so the loader understands the note, and a patchelf change to write
it. It is a staging mass rebuild, because patching glibc rebuilds the world.
pennae’s draft was closed for lack of a go or no go decision rather than any
technical failure; the main worry raised was the long term maintenance of a
glibc patch.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;approach-4-a-guix-style-per-package-ldsocache&quot;&gt;Approach 4: a Guix style per package ld.so.cache&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Guix solves the same problem in production by shipping a per package
&lt;code dir=&quot;auto&quot;&gt;ld.so.cache&lt;/code&gt;, the same binary format &lt;code dir=&quot;auto&quot;&gt;ldconfig&lt;/code&gt; produces, and having a patched
loader consult it (written up in their
&lt;a href=&quot;https://guix.gnu.org/en/blog/2021/taming-the-stat-storm-with-a-loader-cache/&quot;&gt;&lt;em&gt;Taming the ‘stat’ storm with a loader cache&lt;/em&gt;&lt;/a&gt;;
&lt;a href=&quot;https://github.com/NixOS/nixpkgs/issues/207061&quot;&gt;#207061&lt;/a&gt; proposed it for
nixpkgs). It preserves &lt;code dir=&quot;auto&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt; and is proven at scale,
but building the cache needs &lt;code dir=&quot;auto&quot;&gt;ldconfig&lt;/code&gt;/&lt;code dir=&quot;auto&quot;&gt;ldd&lt;/code&gt; for the target architecture, which
breaks cross compilation, and it hits &lt;code dir=&quot;auto&quot;&gt;buildEnv&lt;/code&gt; collisions and &lt;code dir=&quot;auto&quot;&gt;dlmopen&lt;/code&gt;
namespace issues. The ELF note (approach 3) was in part a response: it reads
&lt;code dir=&quot;auto&quot;&gt;DT_NEEDED&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;DT_RUNPATH&lt;/code&gt; statically and never runs a foreign binary, so it
keeps the same &lt;code dir=&quot;auto&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt; guarantee without those costs.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;approach-5-delete-the-loader-with-static-linking&quot;&gt;Approach 5: delete the loader with static linking&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The four approaches above all make the loader’s job easier. Static linking
removes the loader instead. For devenv, a self contained CLI, we spiked it:
building the whole closure through &lt;code dir=&quot;auto&quot;&gt;pkgsStatic&lt;/code&gt; (which means musl, since glibc
doesn’t support a complete static link) drops &lt;code dir=&quot;auto&quot;&gt;devenv version&lt;/code&gt; and
&lt;code dir=&quot;auto&quot;&gt;hook-should-activate&lt;/code&gt; from about 70ms to about 16ms.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Build&lt;/th&gt;
&lt;th&gt;Loaded libraries&lt;/th&gt;
&lt;th&gt;startup&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Baseline (all dynamic, glibc)&lt;/td&gt;
&lt;td&gt;83&lt;/td&gt;
&lt;td&gt;~70ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fully static (musl)&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;~16ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This is not a nixpkgs fix and was never meant to be. Deleting the loader also
deletes everything the loader does at runtime: loading plugins on demand,
honouring driver and interposer overrides, swapping in the GPU vendor’s GL
stack. A lot of nixpkgs depends on that, so static linking can never be a
general default. It works for devenv only because devenv is a self contained CLI
that talks to Nix through its own linked in C API and needs none of it.&lt;/p&gt;
&lt;p&gt;One thing surprised us: at 16ms, with the loader gone, devenv is still far above
the ~2ms a static musl hello world starts in, the rest being &lt;code dir=&quot;auto&quot;&gt;execve&lt;/code&gt; mapping
the image and devenv’s own startup work. Even so, 16ms is fast enough for the
shell hook to drop its per directory activation cache and just run the check
every prompt.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;what-about-macos&quot;&gt;What about macOS?&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;macOS uses a different loader, &lt;code dir=&quot;auto&quot;&gt;dyld&lt;/code&gt;, and the storm isn’t there. Nix on Darwin
already ships approach 1: every Mach-O records its dependencies as absolute
store paths in &lt;code dir=&quot;auto&quot;&gt;LC_LOAD_DYLIB&lt;/code&gt; rather than bare sonames, and carries no
&lt;code dir=&quot;auto&quot;&gt;LC_RPATH&lt;/code&gt;. So &lt;code dir=&quot;auto&quot;&gt;dyld&lt;/code&gt; opens each library directly on the first path it tries,
and system frameworks come straight from the in memory dyld shared cache without
touching disk. Where the glibc &lt;code dir=&quot;auto&quot;&gt;devenv&lt;/code&gt; made ~486 failing opens, the macOS one
makes essentially none.&lt;/p&gt;
&lt;p&gt;The startup cost macOS does have is specific to Nix. To decide whether to
advertise &lt;code dir=&quot;auto&quot;&gt;x86_64-darwin&lt;/code&gt; as an extra platform, libstore forked a child running
&lt;code dir=&quot;auto&quot;&gt;arch -arch x86_64 /usr/bin/true&lt;/code&gt; on startup, costing ~13ms on every Nix process
on Apple silicon. The fix answers the same question with a &lt;code dir=&quot;auto&quot;&gt;stat&lt;/code&gt; of Rosetta 2’s
fixed install path in ~0.01ms
(&lt;a href=&quot;https://github.com/NixOS/nix/pull/16067&quot;&gt;NixOS/nix#16067&lt;/a&gt;).&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;side-by-side&quot;&gt;Side by side&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Every column is framed as a property you &lt;em&gt;want&lt;/em&gt;, so ✅ is always good and ❌
always a cost. Legend: ✅ yes · ⚠️ with caveats · ❌ no · ➖ not applicable.
Caveats marked ⚠️ or worth a word are footnoted below.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;No glibc fork&lt;/th&gt;
&lt;th&gt;No patchelf change&lt;/th&gt;
&lt;th&gt;Cheap on disk&lt;/th&gt;
&lt;th&gt;Keeps &lt;code dir=&quot;auto&quot;&gt;LD_LIBRARY_PATH&lt;/code&gt; / glvnd&lt;/th&gt;
&lt;th&gt;Keeps dup sonames&lt;/th&gt;
&lt;th&gt;Kills hwcaps floor&lt;/th&gt;
&lt;th&gt;Cross safe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Absolute &lt;code dir=&quot;auto&quot;&gt;DT_NEEDED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ &lt;sup&gt;a&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;⚠️ &lt;sup&gt;b&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️ &lt;sup&gt;c&lt;/sup&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RUNPATH symlink farm&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ &lt;sup&gt;d&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;❌ &lt;sup&gt;e&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per DSO ELF note&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per package ld.so.cache&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;⚠️ &lt;sup&gt;f&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static linking (musl)&lt;/td&gt;
&lt;td&gt;✅ &lt;sup&gt;g&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ &lt;sup&gt;h&lt;/sup&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;➖&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ &lt;sup&gt;i&lt;/sup&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;sup&gt;a&lt;/sup&gt; stock &lt;code dir=&quot;auto&quot;&gt;patchelf --replace-needed&lt;/code&gt; ·
&lt;sup&gt;b&lt;/sup&gt; breaks on the rare duplicate soname ·
&lt;sup&gt;c&lt;/sup&gt; only the static-resolution variant cross compiles, and it is unbuilt ·
&lt;sup&gt;d&lt;/sup&gt; stock &lt;code dir=&quot;auto&quot;&gt;patchelf --set-rpath&lt;/code&gt; ·
&lt;sup&gt;e&lt;/sup&gt; every ELF gains its own symlink directory in the store ·
&lt;sup&gt;f&lt;/sup&gt; &lt;code dir=&quot;auto&quot;&gt;buildEnv&lt;/code&gt; collisions ·
&lt;sup&gt;g&lt;/sup&gt; uses musl, not glibc, so no glibc fork to maintain ·
&lt;sup&gt;h&lt;/sup&gt; ~82MB binary ·
&lt;sup&gt;i&lt;/sup&gt; via &lt;code dir=&quot;auto&quot;&gt;pkgsStatic&lt;/code&gt;&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-final-approach&quot;&gt;The final approach&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Over the week at &lt;a href=&quot;https://tacosprint.org&quot;&gt;Tacosprint&lt;/a&gt; we revived the &lt;strong&gt;ELF note cache&lt;/strong&gt;, cleaned it up,
and got it built and tested end to end. After a decade in limbo it now works:
the note writer, &lt;code dir=&quot;auto&quot;&gt;patchelf --build-resolution-cache&lt;/code&gt;
(&lt;a href=&quot;https://github.com/NixOS/patchelf/pull/647&quot;&gt;#647&lt;/a&gt;), shipped in
&lt;a href=&quot;https://github.com/NixOS/patchelf/releases/tag/0.19.0&quot;&gt;patchelf 0.19.0&lt;/a&gt;, the
first patchelf release since 0.18.0 in April 2023.&lt;/p&gt;
&lt;p&gt;The last thing to land is
&lt;a href=&quot;https://github.com/NixOS/nixpkgs/pull/535735&quot;&gt;nixpkgs#535735&lt;/a&gt;, which turns the note on
across the whole package set. Because it patches glibc it has to go through
&lt;code dir=&quot;auto&quot;&gt;staging&lt;/code&gt;, which rebuilds the world, so every binary in nixpkgs comes out the
other side resolving its libraries straight from the note. That is also where it
gets exercised at scale, and we’re committed to fixing whatever shakes out as we
go.&lt;/p&gt;
&lt;p&gt;Once it has proven itself there, the longer term goal is to upstream the loader
patch into glibc itself, so the fix isn’t a nixpkgs carry but something every
store based, nix style package manager, guix included, can rely on.&lt;/p&gt;
</content:encoded></item><item><title>devenv 2.1: Nix with zsh, fish, and nushell via libghostty</title><link>https://devenv.sh/blog/2026/05/07/devenv-21-nix-with-zsh-fish-and-nushell-via-libghostty/</link><guid isPermaLink="true">https://devenv.sh/blog/2026/05/07/devenv-21-nix-with-zsh-fish-and-nushell-via-libghostty/</guid><pubDate>Thu, 07 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://devenv.sh/blog/2026/03/05/devenv-20-a-fresh-interface-to-nix/&quot;&gt;devenv 2.0&lt;/a&gt; gave you hot reload, the status line, and instant cache hits, but &lt;code dir=&quot;auto&quot;&gt;devenv shell&lt;/code&gt; always dropped you into bash, and you still needed &lt;code dir=&quot;auto&quot;&gt;direnv&lt;/code&gt; for activation on &lt;code dir=&quot;auto&quot;&gt;cd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v2.1&quot;&gt;devenv 2.1&lt;/a&gt; closes both gaps and adds structured handles for coding agents.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;every-shell-first-class&quot;&gt;Every shell, first class&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;native-zsh-fish-and-nushell&quot;&gt;Native zsh, fish, and nushell&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://devenv.sh/assets/images/devenv-2.1-shell-reloading-zsh.gif&quot; alt=&quot;Shell reloading in zsh&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v2.1&quot;&gt;devenv 2.1&lt;/a&gt; adds native support for &lt;strong&gt;zsh&lt;/strong&gt;, &lt;strong&gt;fish&lt;/strong&gt;, and &lt;strong&gt;nushell&lt;/strong&gt; (&lt;a href=&quot;https://github.com/cachix/devenv/pull/2718&quot;&gt;devenv#2718&lt;/a&gt;) with rcfile generation, environment diff tracking, reload hooks, and prompt integration implemented per shell rather than shimmed through bash. The shell is picked from &lt;code dir=&quot;auto&quot;&gt;$SHELL&lt;/code&gt;, or set explicitly:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;SHELL=/bin/zsh&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Closes &lt;a href=&quot;https://github.com/cachix/devenv/issues/36&quot;&gt;devenv#36&lt;/a&gt; (open since November 2022), &lt;a href=&quot;https://github.com/cachix/devenv/issues/2487&quot;&gt;devenv#2487&lt;/a&gt;, and &lt;a href=&quot;https://github.com/cachix/devenv/issues/2592&quot;&gt;devenv#2592&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;libghostty-under-the-hood&quot;&gt;libghostty under the hood&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;The virtual terminal emulator was replaced with &lt;a href=&quot;https://github.com/niclas-ahden/libghostty-rs&quot;&gt;libghostty&lt;/a&gt;, the terminal engine from &lt;a href=&quot;https://ghostty.org/&quot;&gt;Ghostty&lt;/a&gt;, giving devenv a single VT parser that handles every shell the same way.&lt;/p&gt;
&lt;p&gt;Building libghostty reliably on Nix took upstream patches in &lt;a href=&quot;https://github.com/Uzaaft/libghostty-rs/pull/27&quot;&gt;libghostty-rs#27&lt;/a&gt;, &lt;a href=&quot;https://github.com/ghostty-org/ghostty/pull/12364&quot;&gt;ghostty#12364&lt;/a&gt;, and &lt;a href=&quot;https://github.com/ghostty-org/ghostty/pull/12548&quot;&gt;ghostty#12548&lt;/a&gt;. Thanks to the Ghostty maintainers for landing them.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;auto-reload&quot;&gt;Auto reload&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;2.0 required &lt;code dir=&quot;auto&quot;&gt;Ctrl+Alt+R&lt;/code&gt; to apply environment changes after a rebuild, and that keybind clashed with reverse search on macOS. &lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v2.1&quot;&gt;2.1&lt;/a&gt; re evaluates in the background on file changes and applies the new environment at the next prompt (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2595&quot;&gt;devenv#2595&lt;/a&gt;).&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;auto-activation-without-direnv&quot;&gt;Auto activation without direnv&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://devenv.sh/auto-activation/&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;devenv hook&lt;/code&gt;&lt;/a&gt; replaces direnv for &lt;code dir=&quot;auto&quot;&gt;cd&lt;/code&gt; based activation. Add one line to your shell config:&lt;/p&gt;
&lt;starlight-tabs&gt;&lt;div&gt;&lt;ul role=&quot;tablist&quot;&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-60&quot; id=&quot;tab-60&quot; aria-selected=&quot;true&quot; tabindex=&quot;0&quot;&gt;Bash&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-61&quot; id=&quot;tab-61&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Zsh&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-62&quot; id=&quot;tab-62&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Fish&lt;/a&gt;&lt;/li&gt;&lt;li role=&quot;presentation&quot;&gt;&lt;a role=&quot;tab&quot; href=&quot;#tab-panel-63&quot; id=&quot;tab-63&quot; aria-selected=&quot;false&quot; tabindex=&quot;-1&quot;&gt;Nushell&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-60&quot; aria-labelledby=&quot;tab-60&quot; role=&quot;tabpanel&quot;&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;~/.bashrc&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;eval&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;$(&lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; hook bash)&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-61&quot; aria-labelledby=&quot;tab-61&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;~/.zshrc&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;eval&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;$(&lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; hook zsh)&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-62&quot; aria-labelledby=&quot;tab-62&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;~/.config/fish/config.fish&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; hook fish | &lt;/span&gt;&lt;span&gt;source&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id=&quot;tab-panel-63&quot; aria-labelledby=&quot;tab-63&quot; role=&quot;tabpanel&quot; hidden&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;config.nu&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;devenv &lt;/span&gt;&lt;span&gt;hook&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nu&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;save&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--&lt;/span&gt;&lt;span&gt;force&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;~/.cache/devenv/hook.nu&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;source&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;~/.cache/devenv/hook.nu&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/div&gt;&lt;/starlight-tabs&gt;
&lt;p&gt;Activation happens on &lt;code dir=&quot;auto&quot;&gt;cd&lt;/code&gt; into a trusted directory and reverses on the way out. No &lt;code dir=&quot;auto&quot;&gt;.envrc&lt;/code&gt;, no external dependencies. Trust is managed with &lt;code dir=&quot;auto&quot;&gt;devenv allow&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;devenv revoke&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;for-coding-agents&quot;&gt;For coding agents&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;In 2.0, an agent that wanted to restart your API after a config change had to kill the whole devenv session or scrape the TUI through ANSI codes. &lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v2.1&quot;&gt;2.1&lt;/a&gt; replaces that with structured handles.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;process-management-from-the-command-line&quot;&gt;Process management from the command line&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;New subcommands act on a running &lt;code dir=&quot;auto&quot;&gt;devenv up&lt;/code&gt; (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2621&quot;&gt;devenv#2621&lt;/a&gt;):&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;logs&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;api&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;restart&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;api&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;stop&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;worker&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;worker&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;These work with the native process manager and are also exposed as MCP tools.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;quiet-mode-by-default&quot;&gt;Quiet mode by default&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;devenv detects agents via &lt;code dir=&quot;auto&quot;&gt;CLAUDECODE&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;OPENCODE_CLIENT&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;AI_AGENT&lt;/code&gt; and switches to quiet mode automatically, suppressing TUI progress output that would waste tokens (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2723&quot;&gt;devenv#2723&lt;/a&gt;). Override with &lt;code dir=&quot;auto&quot;&gt;--verbose&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;--tui&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;opentelemetry-trace-export&quot;&gt;OpenTelemetry trace export&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v2.1&quot;&gt;devenv 2.1&lt;/a&gt; exports OTLP traces (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2415&quot;&gt;devenv#2415&lt;/a&gt;). Every Nix evaluation, derivation build, task run, and managed process becomes a span with attributes like &lt;code dir=&quot;auto&quot;&gt;devenv.activity.kind&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;devenv.derivation_path&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;devenv.url&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;devenv.outcome&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Enable it through the new unified &lt;code dir=&quot;auto&quot;&gt;--trace-to&lt;/code&gt; flag:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--trace-to&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;otlp-grpc&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--trace-to&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;otlp-http-protobuf:http://localhost:4318&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Three OTLP formats are supported: &lt;code dir=&quot;auto&quot;&gt;otlp-grpc&lt;/code&gt; (built in), &lt;code dir=&quot;auto&quot;&gt;otlp-http-protobuf&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;otlp-http-json&lt;/code&gt; (opt in via cargo features). Endpoints can be set on the flag or via the standard &lt;code dir=&quot;auto&quot;&gt;OTEL_EXPORTER_OTLP_*&lt;/code&gt; variables.&lt;/p&gt;
&lt;p&gt;Trace context propagates across process boundaries: spawned tasks, shell commands, and processes inherit &lt;code dir=&quot;auto&quot;&gt;TRACEPARENT&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;TRACESTATE&lt;/code&gt;, so instrumented children show up on the same trace as the parent &lt;code dir=&quot;auto&quot;&gt;devenv up&lt;/code&gt; run.&lt;/p&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;--trace-to&lt;/code&gt; replaces &lt;code dir=&quot;auto&quot;&gt;--trace-output&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;--trace-format&lt;/code&gt; with a single &lt;code dir=&quot;auto&quot;&gt;[format:]destination&lt;/code&gt; syntax, and accepts multiple destinations:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--trace-to&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pretty:stderr&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--trace-to&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;otlp-grpc&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;DEVENV_TRACE_TO=json:file:/tmp/trace.json,otlp-grpc&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;tasks-and-processes&quot;&gt;Tasks and processes&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;devenv tasks run&lt;/code&gt; defaults to &lt;code dir=&quot;auto&quot;&gt;before&lt;/code&gt; mode, so dependencies run too (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2551&quot;&gt;devenv#2551&lt;/a&gt;); &lt;code dir=&quot;auto&quot;&gt;--mode single&lt;/code&gt; restores the old behavior. The same &lt;code dir=&quot;auto&quot;&gt;--mode&lt;/code&gt; flag now also controls which processes &lt;code dir=&quot;auto&quot;&gt;devenv up&lt;/code&gt; starts (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2721&quot;&gt;devenv#2721&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Tasks can print messages on shell entry by writing to &lt;code dir=&quot;auto&quot;&gt;$DEVENV_TASK_OUTPUT_FILE&lt;/code&gt; (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2500&quot;&gt;devenv#2500&lt;/a&gt;).&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;and-more&quot;&gt;And more&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Nix 2.34.&lt;/strong&gt; Multithreaded tarball unpacking, evaluator performance improvements, and REPL enhancements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;require_version&lt;/code&gt; in devenv.yaml.&lt;/strong&gt; Enforce a minimum devenv CLI version for your project. Set &lt;code dir=&quot;auto&quot;&gt;require_version: true&lt;/code&gt; to match the modules version, or use a constraint string like &lt;code dir=&quot;auto&quot;&gt;&quot;&gt;=2.1&quot;&lt;/code&gt; (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2391&quot;&gt;devenv#2391&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ROCm support.&lt;/strong&gt; New &lt;code dir=&quot;auto&quot;&gt;nixpkgs.rocmSupport&lt;/code&gt; option for enabling ROCm in nixpkgs configuration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Full stack traces on error.&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;show-trace&lt;/code&gt; is now always enabled, so evaluation errors include the full stack trace instead of a truncated message suggesting a nonexistent &lt;code dir=&quot;auto&quot;&gt;--show-trace&lt;/code&gt; flag (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2725&quot;&gt;devenv#2725&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ctrl+X to stop processes.&lt;/strong&gt; Stop individual processes from the TUI while keeping them visible and restartable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ctrl+H to hide stopped processes.&lt;/strong&gt; Toggle hiding stopped processes in the TUI to focus on what’s still running. Failed processes stay visible, and the process count shows how many are hidden (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2692&quot;&gt;devenv#2692&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Port allocation fixes.&lt;/strong&gt; Port values (&lt;code dir=&quot;auto&quot;&gt;config.processes.&amp;#x3C;name&gt;.ports.&amp;#x3C;port&gt;.value&lt;/code&gt;) now resolve correctly in &lt;code dir=&quot;auto&quot;&gt;devenv shell&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;devenv tasks run&lt;/code&gt;, matching the ports allocated by &lt;code dir=&quot;auto&quot;&gt;devenv up&lt;/code&gt; (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2710&quot;&gt;devenv#2710&lt;/a&gt;). Ports bound to &lt;code dir=&quot;auto&quot;&gt;0.0.0.0&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;[::]&lt;/code&gt; are now detected, preventing multiple devenv instances from allocating the same port (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2567&quot;&gt;devenv#2567&lt;/a&gt;). Strict port restarts no longer fail with “port already in use” during kernel socket teardown (&lt;a href=&quot;https://github.com/cachix/devenv/pull/2647&quot;&gt;devenv#2647&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dozens of other bug fixes.&lt;/strong&gt; File watcher deduplication, import precedence, eval cache consistency, process lifecycle fixes, and terminal compatibility improvements. See the full &lt;a href=&quot;https://github.com/cachix/devenv/blob/main/CHANGELOG.md&quot;&gt;changelog&lt;/a&gt; for details.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;devenv tasks run&lt;/code&gt;&lt;/strong&gt; now runs dependencies by default (&lt;code dir=&quot;auto&quot;&gt;before&lt;/code&gt; mode instead of &lt;code dir=&quot;auto&quot;&gt;single&lt;/code&gt;). Use &lt;code dir=&quot;auto&quot;&gt;--mode single&lt;/code&gt; for the old behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;final-words&quot;&gt;Final words&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/issues&quot;&gt;Open an issue&lt;/a&gt; or join the &lt;a href=&quot;https://discord.gg/naMgvexb6q&quot;&gt;Discord&lt;/a&gt; with feedback.&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;</content:encoded></item><item><title>devenv 2.0: A Fresh Interface to Nix</title><link>https://devenv.sh/blog/2026/03/05/devenv-20-a-fresh-interface-to-nix/</link><guid isPermaLink="true">https://devenv.sh/blog/2026/03/05/devenv-20-a-fresh-interface-to-nix/</guid><pubDate>Thu, 05 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You type &lt;code dir=&quot;auto&quot;&gt;nix develop&lt;/code&gt;. The terminal fills with a single cryptic line: copying path, 47 of 312, 28.3 MiB, something something NAR. Five seconds. Ten. Is it evaluating? Downloading? Both? You change one line in your config and wait again. When it finally drops you into a shell, you switch to another branch and direnv hijacks your prompt for a rebuild you didn’t ask for. You switch back, and Nix evaluates everything from scratch, even though nothing changed.&lt;/p&gt;
&lt;p&gt;Nix gives you reproducibility that nothing else can match. But the moment to moment experience of &lt;em&gt;using&lt;/em&gt; it has never matched the power underneath.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v2.0&quot;&gt;devenv 2.0&lt;/a&gt; polishes Nix developer experience. Keeps the power, removes frictions. Here’s what that looks like.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;interactive&quot;&gt;Interactive&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;To fully leverage what’s going on in your development shell, we’ve made it fully interactive.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;terminal-ui&quot;&gt;Terminal UI&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Every devenv command now shows a live terminal interface. Instead of scrolling Nix build logs, you see structured progress: what Nix is evaluating, how many derivations need to be built and downloaded, &lt;a href=&quot;https://devenv.sh/tasks/&quot;&gt;task&lt;/a&gt; execution with dependency hierarchy, and error details that expand automatically on failure.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://devenv.sh/assets/images/devenv-2.0-tui.gif&quot; alt=&quot;Terminal UI&quot;&gt;&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;native-shell-reloading&quot;&gt;Native shell reloading&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;You save a file, direnv fires, your prompt locks up for thirty seconds while Nix rebuilds, and you sit there staring at a frozen terminal.&lt;/p&gt;
&lt;p&gt;With native shell, you save a file, devenv rebuilds in the background, a status line at the bottom of your terminal shows progress, and you press &lt;code dir=&quot;auto&quot;&gt;Ctrl+Alt+R&lt;/code&gt; when you’re ready to apply the new environment. Your shell stays interactive the entire time. If the rebuild fails, the error appears in the status line without disrupting your session.&lt;/p&gt;
&lt;p&gt;An example empty environment with only &lt;code dir=&quot;auto&quot;&gt;joe&lt;/code&gt; package:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;packages&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;joe&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://devenv.sh/assets/images/devenv-2.0-shell-reloading.gif&quot; alt=&quot;Shell reloading&quot;&gt;&lt;/p&gt;
&lt;p&gt;Shell reloading is currently supported for bash, with fish and zsh coming soon (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2487&quot;&gt;#2487&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;direnv isn’t needed anymore with &lt;code dir=&quot;auto&quot;&gt;devenv shell&lt;/code&gt; but it’s still supported for automatic activation when switching directories; see the &lt;a href=&quot;https://devenv.sh/integrations/direnv/&quot;&gt;direnv integration&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;native-process-manager&quot;&gt;Native process manager&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;devenv 2.0 ships a built in Rust process manager that replaces process-compose.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devenv.sh/processes/#dependencies&quot;&gt;Dependency ordering&lt;/a&gt;, &lt;a href=&quot;https://devenv.sh/processes/#restart-policies&quot;&gt;restart policies&lt;/a&gt;, &lt;a href=&quot;https://devenv.sh/processes/#ready-probes&quot;&gt;readiness probes&lt;/a&gt; (exec, HTTP, and systemd notify), &lt;a href=&quot;https://devenv.sh/processes/#socket-activation&quot;&gt;systemd socket activation&lt;/a&gt;, &lt;a href=&quot;https://devenv.sh/processes/#watchdog&quot;&gt;watchdog heartbeats&lt;/a&gt;, &lt;a href=&quot;https://devenv.sh/processes/#file-watching&quot;&gt;file watching&lt;/a&gt;, and &lt;a href=&quot;https://devenv.sh/processes/#automatic-port-allocation&quot;&gt;port allocation&lt;/a&gt;. All declarative, all in one place. Dependencies use &lt;code dir=&quot;auto&quot;&gt;@ready&lt;/code&gt; by default (wait for the probe to pass) or &lt;code dir=&quot;auto&quot;&gt;@completed&lt;/code&gt; (wait for the process to exit). You can freely mix &lt;a href=&quot;https://devenv.sh/processes/&quot;&gt;processes&lt;/a&gt; and &lt;a href=&quot;https://devenv.sh/tasks/&quot;&gt;tasks&lt;/a&gt; in the same dependency chains.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;postgres&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;api&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;python3&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/bin/python -m http.server &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;api&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ports&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;after&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;devenv:processes:postgres&quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;ports&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;allocate&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;8080&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;ready&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;port&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;api&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ports&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;path&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;/&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;worker&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;echo &quot;Worker connected to API on port &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;api&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ports&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;exec sleep infinity&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;after&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;devenv:processes:api&quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;https://devenv.sh/assets/images/devenv-2.0-process-manager.gif&quot; alt=&quot;Process manager&quot;&gt;&lt;/p&gt;
&lt;p&gt;This foundation opens the door to a fully integrated development loop: &lt;a href=&quot;https://github.com/cachix/devenv/issues/2527&quot;&gt;running processes in the background directly from your shell session&lt;/a&gt;, and &lt;a href=&quot;https://github.com/cachix/devenv/issues/2519&quot;&gt;automatically restarting them when the shell reloads&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;process-compose is still available via &lt;code dir=&quot;auto&quot;&gt;process.manager.implementation = &quot;process-compose&quot;&lt;/code&gt;. If something is missing from the native manager, &lt;a href=&quot;https://github.com/cachix/devenv/issues&quot;&gt;let us know&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;instant&quot;&gt;Instant&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Run &lt;code dir=&quot;auto&quot;&gt;devenv shell&lt;/code&gt;. Wait a few seconds while Nix evaluates your configuration and builds what’s needed. Now run it again.&lt;/p&gt;
&lt;p&gt;This time it takes milliseconds.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://devenv.sh/assets/images/devenv-2.0-instant.gif&quot; alt=&quot;Instant&quot;&gt;&lt;/p&gt;
&lt;p&gt;Most of the performance gain comes from replacing multiple &lt;code dir=&quot;auto&quot;&gt;nix&lt;/code&gt; CLI invocations with a C FFI backend built on &lt;a href=&quot;https://github.com/nixops4/nix-bindings-rust&quot;&gt;nix-bindings-rust&lt;/a&gt;. Instead of spawning five or more separate Nix processes per command, devenv 2.0 calls the Nix evaluator and store directly through the C API, evaluating one attribute at a time. This also gives us better error messages and real time progress in the TUI. We currently carry patches against Nix to extend the C FFI interface, but these are fully upstreamable and we plan to contribute them back. Thanks to &lt;a href=&quot;https://github.com/roberth&quot;&gt;Robert Hensing&lt;/a&gt; for creating nix-bindings-rust and making this possible.&lt;/p&gt;
&lt;p&gt;This makes the &lt;a href=&quot;https://devenv.sh/blog/2024/10/03/devenv-13-instant-developer-environments-with-nix-caching/&quot;&gt;evaluation cache&lt;/a&gt; incremental. Each evaluated attribute is cached individually along with the files and environment variables it touched. When you change one thing, only the attributes that depend on that change are re-evaluated; everything else is served from cache. A single evaluation now covers &lt;code dir=&quot;auto&quot;&gt;devenv shell&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;devenv test&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;devenv build&lt;/code&gt;, and every other command. When nothing changed (verified by content hash), the cached result is returned immediately without invoking Nix at all.&lt;/p&gt;
&lt;p&gt;The cache invalidates when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any source file that was read during evaluation changes&lt;/li&gt;
&lt;li&gt;Environment variables that were accessed during evaluation change&lt;/li&gt;
&lt;li&gt;The devenv version, system, or configuration options change&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can force a refresh with &lt;code dir=&quot;auto&quot;&gt;--refresh-eval-cache&lt;/code&gt; or disable caching with &lt;code dir=&quot;auto&quot;&gt;--no-eval-cache&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;polyrepo-support&quot;&gt;Polyrepo support&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Most teams don’t live in a single repo. You have a backend in one repository, a frontend in another, shared libraries in a third.&lt;/p&gt;
&lt;p&gt;Referencing outputs from another devenv project was the &lt;a href=&quot;https://github.com/cachix/devenv/issues/1438&quot;&gt;third most upvoted issue&lt;/a&gt;. Now you can reference any option or output from another project through &lt;a href=&quot;https://devenv.sh/inputs/&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;inputs.&amp;#x3C;name&gt;.devenv.config&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;inputs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;my-service&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;github:myorg/my-service&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;flake&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;inputs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;let&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;my-service&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;inputs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;my-service&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;outputs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;my-service&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;packages&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;my-service&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;my-service&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;my-service&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/bin/my-service&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This builds on the existing &lt;a href=&quot;https://devenv.sh/guides/monorepo/&quot;&gt;monorepo&lt;/a&gt; support and extends it to multi-repository workflows. See the &lt;a href=&quot;https://devenv.sh/guides/polyrepo/&quot;&gt;polyrepo guide&lt;/a&gt; for full documentation.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;out-of-tree-devenvs&quot;&gt;Out of tree devenvs&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Not every project has a &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; checked in, and sometimes you want one configuration to serve multiple repositories. This was the &lt;a href=&quot;https://github.com/cachix/devenv/issues/67&quot;&gt;fourth most upvoted issue&lt;/a&gt;. devenv 2.0 adds &lt;a href=&quot;https://devenv.sh/ad-hoc-developer-environments/&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;--from&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;github:myorg/devenv-configs?dir=rust-web&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;path:../shared-config&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Works with &lt;code dir=&quot;auto&quot;&gt;devenv shell&lt;/code&gt;, &lt;a href=&quot;https://devenv.sh/tests/&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;devenv test&lt;/code&gt;&lt;/a&gt;, and &lt;code dir=&quot;auto&quot;&gt;devenv build&lt;/code&gt;. Currently &lt;code dir=&quot;auto&quot;&gt;--from&lt;/code&gt; only works with projects that use &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; alone; &lt;a href=&quot;https://github.com/cachix/devenv/issues/2205&quot;&gt;projects that also rely on &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt; for extra inputs aren’t supported yet&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;for-coding-agents&quot;&gt;For coding agents&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;A coding agent spins up your project in the background. It starts the dev server. Port 8080 is already taken by another agent running the same project. The process crashes. The agent retries, hits the same port, crashes again.&lt;/p&gt;
&lt;p&gt;Meanwhile, that agent has full read access to every &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; file in your project. Your API keys, database credentials, third party tokens. It never asks permission. It never tells you what it read.&lt;/p&gt;
&lt;p&gt;devenv 2.0 fixes both problems.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;automatic-port-allocation&quot;&gt;Automatic port allocation&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Define named &lt;a href=&quot;https://devenv.sh/processes/#automatic-port-allocation&quot;&gt;ports&lt;/a&gt; and devenv finds free ones automatically:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;server&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;ports&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;allocate&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;8080&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;python -m http.server &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;toString&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;server&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;ports&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;http&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;value&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If port 8080 is taken, devenv tries 8081, 8082, and so on. Ports are held during evaluation to prevent races, then released just before the process starts. Use &lt;code dir=&quot;auto&quot;&gt;devenv up --strict-ports&lt;/code&gt; to fail instead of searching.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;secret-isolation-with-secretspec&quot;&gt;Secret isolation with SecretSpec&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;devenv 2.0 ships with &lt;a href=&quot;https://secretspec.dev&quot;&gt;SecretSpec 0.7.2&lt;/a&gt; for declarative, provider-agnostic secrets management. Declare what secrets your project needs in &lt;code dir=&quot;auto&quot;&gt;secretspec.toml&lt;/code&gt;, and each developer provides them from their preferred backend: keyring, dotenv, 1Password, or environment variables.&lt;/p&gt;
&lt;p&gt;Here’s the thing: because password managers prompt for credentials before giving them out, secrets are never silently leaked to agents running in the background. This is a fundamental difference from &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; files that any process can read.&lt;/p&gt;
&lt;p&gt;Let’s declare some secrets:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;secretspec.toml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[project]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;name = &lt;/span&gt;&lt;span&gt;&quot;myapp&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;revision = &lt;/span&gt;&lt;span&gt;&quot;1.0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[profiles.default]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;DATABASE_URL = { description = &lt;/span&gt;&lt;span&gt;&quot;PostgreSQL connection string&quot;&lt;/span&gt;&lt;span&gt;, required = &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;STRIPE_KEY = { description = &lt;/span&gt;&lt;span&gt;&quot;Stripe API secret key&quot;&lt;/span&gt;&lt;span&gt;, required = &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;SENTRY_DSN = { description = &lt;/span&gt;&lt;span&gt;&quot;Sentry error tracking DSN&quot;&lt;/span&gt;&lt;span&gt;, required = &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And see how devenv asks for them and starts:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://devenv.sh/assets/images/devenv-2.0-secretspec.gif&quot; alt=&quot;SecretSpec&quot;&gt;&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;mcp-server&quot;&gt;MCP server&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;The devenv MCP server exposes package and option search over stdio and HTTP:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;mcp&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--http&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;8080&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We host a public instance at &lt;code dir=&quot;auto&quot;&gt;mcp.devenv.sh&lt;/code&gt; that any MCP compatible tool can query without needing a local devenv installation.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devenv.new&quot;&gt;devenv.new&lt;/a&gt; is a coding agent powered by the same package and option search that generates &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; files for you.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;and-more&quot;&gt;And more&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Language servers for your code.&lt;/strong&gt; Most language modules now have &lt;code dir=&quot;auto&quot;&gt;lsp.enable&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;lsp.package&lt;/code&gt; options, giving you a language server for your project out of the box.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Language server for &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt;.&lt;/strong&gt; Get completion and diagnostics while editing your devenv configuration:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lsp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;devenv eval&lt;/code&gt;.&lt;/strong&gt; Evaluate any attribute in &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; and return JSON:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;eval&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;languages.rust.channel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;services.postgres.enable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;languages.rust.channel&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;stable&quot;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;services.postgres.enable&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;devenv build&lt;/code&gt; returns JSON.&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;devenv build&lt;/code&gt; now outputs structured JSON mapping attribute names to store paths:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;languages.rust.channel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;services.postgres.enable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;languages.rust.channel&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;/nix/store/...-stable&quot;,&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;&quot;services.postgres.enable&quot;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;/nix/store/...-postgresql-16.6&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;NIXPKGS_CONFIG.&lt;/strong&gt; devenv now sets a global &lt;code dir=&quot;auto&quot;&gt;NIXPKGS_CONFIG&lt;/code&gt; environment variable, ensuring that nixpkgs configuration (like &lt;code dir=&quot;auto&quot;&gt;allowUnfree&lt;/code&gt;, CUDA settings) is &lt;a href=&quot;https://github.com/cachix/devenv/issues/1090&quot;&gt;consistently applied across all Nix operations&lt;/a&gt; within the environment.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;breaking-changes&quot;&gt;Breaking changes&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;For a step by step upgrade guide, see &lt;a href=&quot;https://devenv.sh/guides/migrating-to-20/&quot;&gt;Migrating to devenv 2.0&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://devenv.sh/git-hooks/&quot;&gt;&lt;code dir=&quot;auto&quot;&gt;git-hooks&lt;/code&gt;&lt;/a&gt; input is no longer included by default. If you use &lt;code dir=&quot;auto&quot;&gt;git-hooks.hooks&lt;/code&gt;, add it to your &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;devenv container --copy &amp;#x3C;name&gt;&lt;/code&gt; has been removed. Use &lt;code dir=&quot;auto&quot;&gt;devenv container copy &amp;#x3C;name&gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;devenv build&lt;/code&gt; now outputs JSON instead of plain store paths. Update any scripts that parse the output.&lt;/li&gt;
&lt;li&gt;The native process manager is now the default. Set &lt;code dir=&quot;auto&quot;&gt;process.manager.implementation = &quot;process-compose&quot;&lt;/code&gt; if you need the old behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;deprecation-of-devenv-0x&quot;&gt;Deprecation of devenv 0.x&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;devenv 0.x is now deprecated. Support will be dropped entirely in devenv 3.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;final-words&quot;&gt;Final words&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Over the next few weeks we will be focused on fixing bugs and stabilizing the release. If you run into any issues, please &lt;a href=&quot;https://github.com/cachix/devenv/issues&quot;&gt;open a report&lt;/a&gt; and we will prioritize it. Join the &lt;a href=&quot;https://discord.gg/naMgvexb6q&quot;&gt;devenv Discord community&lt;/a&gt; to share feedback!&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>SecretSpec 0.7: Declarative Secret Generation</title><link>https://devenv.sh/blog/2026/02/09/secretspec-07-declarative-secret-generation/</link><guid isPermaLink="true">https://devenv.sh/blog/2026/02/09/secretspec-07-declarative-secret-generation/</guid><pubDate>Mon, 09 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you haven’t tried SecretSpec yet, see &lt;a href=&quot;https://devenv.sh/blog/2025/07/21/announcing-secretspec-declarative-secrets-management/&quot;&gt;Announcing SecretSpec&lt;/a&gt; for an introduction.&lt;/p&gt;
&lt;p&gt;SecretSpec 0.7 introduces &lt;strong&gt;declarative secret generation&lt;/strong&gt; — declare that secrets should be auto-generated when missing, directly in your &lt;code dir=&quot;auto&quot;&gt;secretspec.toml&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;When onboarding to a project, developers typically need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read docs to understand which secrets are needed&lt;/li&gt;
&lt;li&gt;Manually generate passwords and tokens&lt;/li&gt;
&lt;li&gt;Store them in the right provider&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Some secrets — like local database passwords or session keys — don’t need to be shared at all. They just need to exist.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-solution-type--generate&quot;&gt;The Solution: &lt;code dir=&quot;auto&quot;&gt;type&lt;/code&gt; + &lt;code dir=&quot;auto&quot;&gt;generate&lt;/code&gt;&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Add &lt;code dir=&quot;auto&quot;&gt;type&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;generate&lt;/code&gt; to any secret declaration, and SecretSpec handles the rest:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[project]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;name = &lt;/span&gt;&lt;span&gt;&quot;my-app&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;revision = &lt;/span&gt;&lt;span&gt;&quot;1.0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[profiles.default]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;DB_PASSWORD = { description = &lt;/span&gt;&lt;span&gt;&quot;Database password&quot;&lt;/span&gt;&lt;span&gt;, type = &lt;/span&gt;&lt;span&gt;&quot;password&quot;&lt;/span&gt;&lt;span&gt;, generate = &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;API_TOKEN = { description = &lt;/span&gt;&lt;span&gt;&quot;Internal API token&quot;&lt;/span&gt;&lt;span&gt;, type = &lt;/span&gt;&lt;span&gt;&quot;hex&quot;&lt;/span&gt;&lt;span&gt;, generate = { bytes = &lt;/span&gt;&lt;span&gt;32&lt;/span&gt;&lt;span&gt; } }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;SESSION_KEY = { description = &lt;/span&gt;&lt;span&gt;&quot;Session signing key&quot;&lt;/span&gt;&lt;span&gt;, type = &lt;/span&gt;&lt;span&gt;&quot;base64&quot;&lt;/span&gt;&lt;span&gt;, generate = { bytes = &lt;/span&gt;&lt;span&gt;64&lt;/span&gt;&lt;span&gt; } }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;REQUEST_ID = { description = &lt;/span&gt;&lt;span&gt;&quot;Request ID prefix&quot;&lt;/span&gt;&lt;span&gt;, type = &lt;/span&gt;&lt;span&gt;&quot;uuid&quot;&lt;/span&gt;&lt;span&gt;, generate = &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Run &lt;code dir=&quot;auto&quot;&gt;secretspec check&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;secretspec run&lt;/code&gt;, and any missing secret with &lt;code dir=&quot;auto&quot;&gt;generate&lt;/code&gt; configured is automatically created and stored in your provider:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$ secretspec check&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Checking secrets in my-app (profile: default)...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;✓ DB_PASSWORD - generated and saved to keyring (profile: default)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;✓ API_TOKEN - generated and saved to keyring (profile: default)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;✓ SESSION_KEY - generated and saved to keyring (profile: default)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;✓ REQUEST_ID - generated and saved to keyring (profile: default)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Summary: 4 found, 0 missing&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;On subsequent runs, the stored values are reused — generation is idempotent.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;five-generation-types&quot;&gt;Five Generation Types&lt;/h2&gt;&lt;/div&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Default Output&lt;/th&gt;
&lt;th&gt;Options&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;password&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;32 alphanumeric characters&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;length&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;charset&lt;/code&gt; (&lt;code dir=&quot;auto&quot;&gt;&quot;alphanumeric&quot;&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;&quot;ascii&quot;&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;hex&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;64 hex characters (32 bytes)&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;base64&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;44 characters (32 bytes)&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;bytes&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;uuid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;UUID v4&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;stdout of a shell command&lt;/td&gt;
&lt;td&gt;&lt;code dir=&quot;auto&quot;&gt;command&lt;/code&gt; (required)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;&lt;h3 id=&quot;custom-options&quot;&gt;Custom Options&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Use a table instead of &lt;code dir=&quot;auto&quot;&gt;true&lt;/code&gt; for fine-grained control:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# 64-character password with printable ASCII&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;ADMIN_PASSWORD = { description = &lt;/span&gt;&lt;span&gt;&quot;Admin password&quot;&lt;/span&gt;&lt;span&gt;, type = &lt;/span&gt;&lt;span&gt;&quot;password&quot;&lt;/span&gt;&lt;span&gt;, generate = { length = &lt;/span&gt;&lt;span&gt;64&lt;/span&gt;&lt;span&gt;, charset = &lt;/span&gt;&lt;span&gt;&quot;ascii&quot;&lt;/span&gt;&lt;span&gt; } }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# 64 random bytes, hex-encoded (128 chars)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;ENCRYPTION_KEY = { description = &lt;/span&gt;&lt;span&gt;&quot;Encryption key&quot;&lt;/span&gt;&lt;span&gt;, type = &lt;/span&gt;&lt;span&gt;&quot;hex&quot;&lt;/span&gt;&lt;span&gt;, generate = { bytes = &lt;/span&gt;&lt;span&gt;64&lt;/span&gt;&lt;span&gt; } }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;shell-commands&quot;&gt;Shell Commands&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code dir=&quot;auto&quot;&gt;command&lt;/code&gt; type runs arbitrary shell commands, covering any generation need:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# WireGuard private key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;WG_PRIVATE_KEY = { description = &lt;/span&gt;&lt;span&gt;&quot;WireGuard key&quot;&lt;/span&gt;&lt;span&gt;, type = &lt;/span&gt;&lt;span&gt;&quot;command&quot;&lt;/span&gt;&lt;span&gt;, generate = { command = &lt;/span&gt;&lt;span&gt;&quot;wg genkey&quot;&lt;/span&gt;&lt;span&gt; } }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# MongoDB keyfile&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;MONGO_KEYFILE = { description = &lt;/span&gt;&lt;span&gt;&quot;MongoDB keyfile&quot;&lt;/span&gt;&lt;span&gt;, type = &lt;/span&gt;&lt;span&gt;&quot;command&quot;&lt;/span&gt;&lt;span&gt;, generate = { command = &lt;/span&gt;&lt;span&gt;&quot;openssl rand -base64 765&quot;&lt;/span&gt;&lt;span&gt; } }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# SSH public key (from existing key)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;SSH_PUBKEY = { description = &lt;/span&gt;&lt;span&gt;&quot;SSH public key&quot;&lt;/span&gt;&lt;span&gt;, type = &lt;/span&gt;&lt;span&gt;&quot;command&quot;&lt;/span&gt;&lt;span&gt;, generate = { command = &lt;/span&gt;&lt;span&gt;&quot;ssh-keygen -y -f ~/.ssh/id_ed25519&quot;&lt;/span&gt;&lt;span&gt; } }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;design-decisions&quot;&gt;Design Decisions&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Generate if missing, never overwrite.&lt;/strong&gt; Existing secrets are always preserved. This makes generation safe to declare in shared config files — it only fills in gaps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No separate &lt;code dir=&quot;auto&quot;&gt;generate&lt;/code&gt; command.&lt;/strong&gt; Generation happens automatically during &lt;code dir=&quot;auto&quot;&gt;check&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;run&lt;/code&gt;. A dedicated CLI command for rotation is planned for a future release.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code dir=&quot;auto&quot;&gt;type&lt;/code&gt; without &lt;code dir=&quot;auto&quot;&gt;generate&lt;/code&gt; is valid.&lt;/strong&gt; You can annotate secrets with a type for documentation purposes without enabling generation. This is useful for secrets that must be manually provisioned but benefit from type metadata.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conflicts are caught early.&lt;/strong&gt; &lt;code dir=&quot;auto&quot;&gt;generate&lt;/code&gt; + &lt;code dir=&quot;auto&quot;&gt;default&lt;/code&gt; on the same secret is an error (which value should win?). &lt;code dir=&quot;auto&quot;&gt;type = &quot;command&quot;&lt;/code&gt; with &lt;code dir=&quot;auto&quot;&gt;generate = true&lt;/code&gt; (no command string) is also an error.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;upgrading&quot;&gt;Upgrading&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Update to SecretSpec 0.7 and add &lt;code dir=&quot;auto&quot;&gt;type&lt;/code&gt;/&lt;code dir=&quot;auto&quot;&gt;generate&lt;/code&gt; to any secrets you want auto-generated. Existing configurations continue to work without changes — both fields are optional.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-sSL&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;https://install.secretspec.dev&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;sh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;See the &lt;a href=&quot;https://secretspec.dev/reference/configuration/#secret-generation&quot;&gt;configuration reference&lt;/a&gt; for full documentation.&lt;/p&gt;
&lt;p&gt;Share your thoughts on our &lt;a href=&quot;https://discord.gg/naMgvexb6q&quot;&gt;Discord community&lt;/a&gt; or &lt;a href=&quot;https://github.com/cachix/secretspec/issues&quot;&gt;open an issue on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>devenv 1.11: Module changelogs and SecretSpec 0.4.0</title><link>https://devenv.sh/blog/2025/11/26/devenv-111-module-changelogs-and-secretspec-040/</link><guid isPermaLink="true">https://devenv.sh/blog/2025/11/26/devenv-111-module-changelogs-and-secretspec-040/</guid><pubDate>Wed, 26 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v1.11&quot;&gt;devenv 1.11&lt;/a&gt; brings the following improvements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#module-changelogs&quot;&gt;Module changelogs&lt;/a&gt; for communicating breaking changes&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#profile-configuration-in-devenvyaml&quot;&gt;Profile configuration in devenv.yaml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#secretspec-040&quot;&gt;SecretSpec 0.4.0&lt;/a&gt; with multiple provider support and file-based secrets&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;module-changelogs&quot;&gt;Module changelogs&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The Nix module system already handles renames and deprecations well—you get clear warnings when using old option names. But communicating &lt;em&gt;behavior&lt;/em&gt; changes is harder. When a default value changes or a feature works differently, users often discover this through unexpected behavior rather than explicit notification.&lt;/p&gt;
&lt;p&gt;Recently we’ve wanted to &lt;a href=&quot;https://github.com/cachix/devenv/pull/2304&quot;&gt;change &lt;code dir=&quot;auto&quot;&gt;git-hooks.package&lt;/code&gt;&lt;/a&gt; from &lt;code dir=&quot;auto&quot;&gt;pkgs.pre-commit&lt;/code&gt; to &lt;code dir=&quot;auto&quot;&gt;pkgs.prek&lt;/code&gt;, a reimplementation in Rust.&lt;/p&gt;
&lt;p&gt;The new changelog option lets module authors declare important changes directly in their modules:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;changelogs&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;date&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;2025-11-26&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;title&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;git-hooks.package now defaults to pkgs.prek&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;when&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;git-hooks&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;The git-hooks integration now uses [prek](https://github.com/cachix/prek) by default for speed and smaller binary size.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;If you were using pre-commit hooks, update your configuration:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;```nix&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;git-hooks.package = pkgs.pre-commit;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;```&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Each entry includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;date&lt;/code&gt;: When the change was introduced (YYYY-MM-DD)&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;title&lt;/code&gt;: Short summary of what changed&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;when&lt;/code&gt;: Condition for showing this changelog (show only to affected users)&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;description&lt;/code&gt;: Markdown-formatted details and migration steps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After running &lt;code dir=&quot;auto&quot;&gt;devenv update&lt;/code&gt;, relevant new changelogs are displayed automatically:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;📋&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;changelog&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;2025-11-24:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;**git-hooks.package&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;defaults&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pkgs.prek**&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;The&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;git-hooks&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;integration&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;now&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;uses&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;prek&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;by&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;default.&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;If&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;you&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;were&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;using&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pre-commit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;hooks,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;your&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;configuration:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;git-hooks.package&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pkgs.pre-commit&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code dir=&quot;auto&quot;&gt;when&lt;/code&gt; condition ensures changelogs only appear to users who have the relevant feature enabled. A breaking change to PostgreSQL configuration won’t bother users who don’t use PostgreSQL.&lt;/p&gt;
&lt;p&gt;View all relevant changelogs anytime with:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;changelogs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;for-module-authors&quot;&gt;For module authors&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;If you maintain devenv modules (either in-tree or as external imports), add changelog entries when making breaking changes. This helps your users stay informed without requiring them to read through commit history or release notes.&lt;/p&gt;
&lt;p&gt;See the &lt;a href=&quot;https://devenv.sh/community/contributing/#adding-changelogs-for-breaking-and-behavior-changes&quot;&gt;contributing guide&lt;/a&gt; for details.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;profile-configuration-in-devenvyaml&quot;&gt;Profile configuration in devenv.yaml&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;You can now specify the default profile in &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;devenv.local.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;profile&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;fullstack&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This can be overridden with the &lt;code dir=&quot;auto&quot;&gt;--profile&lt;/code&gt; CLI flag.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;secretspec-040&quot;&gt;SecretSpec 0.4.0&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;We’ve released &lt;a href=&quot;https://secretspec.dev&quot;&gt;SecretSpec 0.4.0&lt;/a&gt; with two major features: multiple provider support and file-based secrets.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;multiple-providers-with-fallback-chains&quot;&gt;Multiple providers with fallback chains&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;You can now configure different providers for individual secrets, with automatic fallback:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;secretspec.toml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[profiles.production]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;DATABASE_URL = { description = &lt;/span&gt;&lt;span&gt;&quot;Production DB&quot;&lt;/span&gt;&lt;span&gt;, providers = [&lt;/span&gt;&lt;span&gt;&quot;prod_vault&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;keyring&quot;&lt;/span&gt;&lt;span&gt;] }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;API_KEY = { description = &lt;/span&gt;&lt;span&gt;&quot;API key&quot;&lt;/span&gt;&lt;span&gt;, providers = [&lt;/span&gt;&lt;span&gt;&quot;env&quot;&lt;/span&gt;&lt;span&gt;] }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Define provider aliases in your user config:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;providers&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;prod_vault&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;onepassword://vault/Production&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;providers&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shared_vault&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;onepassword://vault/Shared&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;When multiple providers are specified, SecretSpec tries each in order until it finds the secret. This enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Shared vs local&lt;/strong&gt;: Try a team vault first, fall back to local keyring&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Migration&lt;/strong&gt;: Gradually move secrets between providers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multi-source setups&lt;/strong&gt;: Projects that need to source secrets from different providers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Combine that with profile-level defaults to avoid repetition:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[profiles.production.defaults]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;providers = [&lt;/span&gt;&lt;span&gt;&quot;prod_vault&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;keyring&quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;required = &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[profiles.production]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;DATABASE_URL = { description = &lt;/span&gt;&lt;span&gt;&quot;Production DB&quot;&lt;/span&gt;&lt;span&gt; }  &lt;/span&gt;&lt;span&gt;# Uses default providers&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;API_KEY = { description = &lt;/span&gt;&lt;span&gt;&quot;API key&quot;&lt;/span&gt;&lt;span&gt;, providers = [&lt;/span&gt;&lt;span&gt;&quot;env&quot;&lt;/span&gt;&lt;span&gt;] }  &lt;/span&gt;&lt;span&gt;# Override&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;provisioning-secrets-as-a-file&quot;&gt;Provisioning secrets as a file&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Some tools require secrets as file paths rather than values—certificates, SSH keys, service account credentials.&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[profiles.default]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;TLS_CERT = { description = &lt;/span&gt;&lt;span&gt;&quot;TLS certificate&quot;&lt;/span&gt;&lt;span&gt;, as_path = &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With &lt;code dir=&quot;auto&quot;&gt;as_path = true&lt;/code&gt;, SecretSpec writes the secret value to a secure temporary file and returns the path instead:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;TLS_CERT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/tmp/secretspec-abc123/TLS_CERT&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In Nix, we don’t want to leak secrets into the world-readable store, so passing them as paths avoids this issue:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;myservices&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;certPath&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;secrets&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;TLS_CERT&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Temporary files are automatically cleaned up when the resolved secrets are dropped.&lt;/p&gt;
&lt;p&gt;If you haven’t tried SecretSpec yet, see &lt;a href=&quot;https://devenv.sh/blog/2025/07/21/announcing-secretspec-declarative-secrets-management/&quot;&gt;Announcing SecretSpec&lt;/a&gt; for an introduction.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;New to devenv? Check out the &lt;a href=&quot;https://devenv.sh/getting-started/&quot;&gt;getting started guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Join the &lt;a href=&quot;https://discord.gg/naMgvexb6q&quot;&gt;devenv Discord community&lt;/a&gt; to share feedback!&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>devenv 1.10: monorepo Nix support with devenv.yaml imports</title><link>https://devenv.sh/blog/2025/10/07/devenv-110-monorepo-nix-support-with-devenvyaml-imports/</link><guid isPermaLink="true">https://devenv.sh/blog/2025/10/07/devenv-110-monorepo-nix-support-with-devenvyaml-imports/</guid><pubDate>Tue, 07 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v1.10&quot;&gt;devenv 1.10&lt;/a&gt; brings new capabilities for structuring monorepo projects:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://devenv.sh/blog/2025/10/07/devenv-110-monorepo-nix-support-with-devenvyaml-imports/#absolute--parent-path-imports&quot;&gt;absolute/parent path imports&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#git-root-prefixing&quot;&gt;git root prefixing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#devenvyaml-imports&quot;&gt;devenv.yaml imports&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#devenvlocalyaml-support&quot;&gt;devenv.local.yaml support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#monorepo-guide&quot;&gt;monorepo guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;absolute--parent-path-imports&quot;&gt;Absolute / parent path imports&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Paths starting with &lt;code dir=&quot;auto&quot;&gt;/&lt;/code&gt; are now resolved from your git repository root, and parent imports are also supported (&lt;a href=&quot;https://github.com/cachix/devenv/issues/998&quot;&gt;#998&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;This lets services consistently reference shared configurations:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;services/worker/devenv.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;imports&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;/nix/devenv.nix&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;../api/devenv.nix&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is particularly handy in monorepos where projects are nested at different depths:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;my-monorepo/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── nix/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;│   └── devenv.nix       # Shared base configuration&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;├── services/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;│   ├── api/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;│   │   └── devenv.yaml  # imports: [/nix]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;│   └── worker/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;│       └── devenv.yaml  # imports: [/nix]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;└── apps/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└── web/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;&lt;span&gt;└── devenv.yaml  # imports: [/nix]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;All three projects reference &lt;code dir=&quot;auto&quot;&gt;/nix&lt;/code&gt; regardless of their location.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;git-root-prefixing&quot;&gt;Git root prefixing&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The new &lt;code dir=&quot;auto&quot;&gt;config.git.root&lt;/code&gt; variable provides the git repository root path for specifying working directories in tasks and processes (&lt;a href=&quot;https://github.com/cachix/devenv/issues/1850&quot;&gt;#1850&lt;/a&gt;, &lt;a href=&quot;https://github.com/cachix/devenv/issues/316&quot;&gt;#316&lt;/a&gt;).&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;services/api/devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&quot;db:migrate&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;npm run migrate&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;cwd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;root&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/services/api&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;api&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;npm start&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;cwd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;root&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/services/api&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Useful when reusing modules across different directories.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;devenvyaml-imports&quot;&gt;devenv.yaml imports&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Most upvoted feature with 75 votes (&lt;a href=&quot;https://github.com/cachix/devenv/issues/14&quot;&gt;#14&lt;/a&gt;) is here!&lt;/p&gt;
&lt;p&gt;Local imports now load and merge both &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt; configurations:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;shared/devenv.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;allowUnfree&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;inputs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;nixpkgs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;github:NixOS/nixpkgs/nixpkgs-unstable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;services/api/devenv.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;imports&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;/shared&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The API service inherits the &lt;code dir=&quot;auto&quot;&gt;allowUnfree&lt;/code&gt; setting and nixpkgs input. Note that this merging only applies to local filesystem imports — imports from inputs still only load Nix configurations (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2205&quot;&gt;#2205&lt;/a&gt;).&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;devenvlocalyaml-support&quot;&gt;devenv.local.yaml support&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Just like &lt;code dir=&quot;auto&quot;&gt;devenv.local.nix&lt;/code&gt;, you can now use &lt;code dir=&quot;auto&quot;&gt;devenv.local.yaml&lt;/code&gt; for developer-specific overrides (&lt;a href=&quot;https://github.com/cachix/devenv/issues/817&quot;&gt;#817&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Both files are git-ignored for local overrides:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.local.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;allowUnfree&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;monorepo-guide&quot;&gt;Monorepo guide&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Check out the new &lt;a href=&quot;https://devenv.sh/guides/monorepo/&quot;&gt;Monorepo Guide&lt;/a&gt; for detailed examples and patterns.&lt;/p&gt;
&lt;p&gt;Join the &lt;a href=&quot;https://discord.gg/naMgvexb6q&quot;&gt;devenv community&lt;/a&gt; to share your monorepo experience!&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>devenv 1.9: Scaling Nix projects using modules and profiles</title><link>https://devenv.sh/blog/2025/09/17/devenv-19-scaling-nix-projects-using-modules-and-profiles/</link><guid isPermaLink="true">https://devenv.sh/blog/2025/09/17/devenv-19-scaling-nix-projects-using-modules-and-profiles/</guid><pubDate>Wed, 17 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://devenv.sh/profiles/&quot;&gt;Profiles&lt;/a&gt; are a new way to organize and selectively activate parts of development environment.&lt;/p&gt;
&lt;p&gt;While we try &lt;a href=&quot;https://en.wikipedia.org/wiki/Convention_over_configuration&quot;&gt;our best to ship sane defaults for languages and services&lt;/a&gt;, each team has its own preferences. We’re &lt;a href=&quot;https://github.com/cachix/devenv/pull/1974&quot;&gt;still working on uniform interface for language configuration&lt;/a&gt; so you’ll be able to customize each bit of the environment.&lt;/p&gt;
&lt;p&gt;Typically, these best practices are created using scaffolds, these quickly go out of date and don’t have
the ability to ship updates in a central place.&lt;/p&gt;
&lt;p&gt;On top of that, when developing in a repository with different components, it’s handy to be able to activate only part of
the development environment.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;extending-devenv-modules&quot;&gt;Extending devenv modules&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Teams can define their own set of recommended best practices in a central repository to create even more opinionated environments:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;mkEnableOption&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Rust development stack&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;database&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;mkEnableOption&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Database services&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;packages&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;mkIf&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cargo-watch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;mkIf&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;nightly&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;postgres&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;mkIf&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;database&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;initialScript&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;CREATE DATABASE myapp;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;We have defined our defaults for &lt;code dir=&quot;auto&quot;&gt;myteam.languages.rust&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;myteam.services.database&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;using-profiles&quot;&gt;Using Profiles&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Once you have your team module defined, you can start using it in new projects:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;inputs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;github:myorg/devenv-myteam&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;flake&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;imports&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This automatically includes your centrally managed module.&lt;/p&gt;
&lt;p&gt;Since options default to &lt;code dir=&quot;auto&quot;&gt;false&lt;/code&gt;, you’ll need to enable them per project. You can enable common defaults globally and use profiles to activate additional components on demand:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;packages&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;jq&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;profiles&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;backend&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;database&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;frontend&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;javascript&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;fullstack&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;extends&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;backend&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;frontend&quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Let’s do some Rust development with the base configuration:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--profile&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;backend&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Using backend profile to launch the database:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--profile&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;backend&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;up&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Using frontend profile for JavaScript development:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--profile&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;frontend&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Using fullstack profile to get both backend and frontend tools (extends both profiles):&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--profile&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fullstack&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The fullstack profile automatically includes everything from both the backend and frontend profiles through extends. Use &lt;a href=&quot;https://devenv.sh/ad-hoc-developer-environments/&quot;&gt;ad-hoc environment options&lt;/a&gt; to further customize:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-P&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fullstack&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-O&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;myteam.languages.rust.enable:bool&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;user-and-hostname-profiles&quot;&gt;User and Hostname Profiles&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Profiles can activate automatically based on hostname or username:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;profiles&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;hostname&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&quot;dev-server&quot;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;database&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&quot;alice&quot;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;When user &lt;code dir=&quot;auto&quot;&gt;alice&lt;/code&gt; runs &lt;code dir=&quot;auto&quot;&gt;devenv shell&lt;/code&gt; on &lt;code dir=&quot;auto&quot;&gt;dev-server&lt;/code&gt; hostname, both her user profile and the hostname profile automatically activate.&lt;/p&gt;
&lt;p&gt;This gives teams fine-grained control over development environments while keeping individual setups simple and centralized.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;profile-priorities&quot;&gt;Profile priorities&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;To keep profile-heavy projects from fighting each other we wrap every profile module in an automatic override priority. The base configuration is applied first, hostname profiles stack on top, then user profiles, and finally any manual &lt;code dir=&quot;auto&quot;&gt;--profile&lt;/code&gt; flags—if you pass several, the last flag wins. Extends chains apply parents before children so overrides land where you expect.&lt;/p&gt;
&lt;p&gt;Here is a simple example where every tier toggles the same option, yet the final value stays deterministic:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;database&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;profiles&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;hostname&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&quot;dev-server&quot;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;database&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;user&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&quot;alice&quot;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;database&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;qa&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;module&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;myteam&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;database&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Alice starting a shell on &lt;code dir=&quot;auto&quot;&gt;dev-server&lt;/code&gt; will see the base configuration turn the database off, the hostname profile enable it, her user profile disable it again, and a manual &lt;code dir=&quot;auto&quot;&gt;devenv --profile qa shell&lt;/code&gt; flip it back on. Even with conflicting assignments, priorities make the outcome predictable and avoid merge conflicts.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;building-linux-containers-on-macos&quot;&gt;Building Linux containers on macOS&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Oh, we’ve also &lt;a href=&quot;https://github.com/cachix/devenv/pull/2085&quot;&gt;removed restriction so you can now build containers on macOS&lt;/a&gt; if you configure a linux builder.&lt;/p&gt;
&lt;p&gt;Containers are likely to get a simplification redesign, as we’ve learned a lot since they were &lt;a href=&quot;https://devenv.sh/blog/2023/03/02/devenv-06-generating-containers-and-instant-shell-activation/&quot;&gt;introduced in devenv 0.6&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;New to devenv? Start with the &lt;a href=&quot;https://devenv.sh/getting-started/&quot;&gt;getting started guide&lt;/a&gt; to learn the basics.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://devenv.sh/profiles/&quot;&gt;profiles documentation&lt;/a&gt; for complete examples.&lt;/p&gt;
&lt;p&gt;Join the &lt;a href=&quot;https://discord.gg/naMgvexb6q&quot;&gt;devenv Discord community&lt;/a&gt; to share how your team uses profiles!&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>Closing the Nix Gap: From Environments to Packaged Applications for Rust</title><link>https://devenv.sh/blog/2025/08/22/closing-the-nix-gap-from-environments-to-packaged-applications-for-rust/</link><guid isPermaLink="true">https://devenv.sh/blog/2025/08/22/closing-the-nix-gap-from-environments-to-packaged-applications-for-rust/</guid><pubDate>Fri, 22 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Should I use crate2nix, cargo2nix, or naersk for packaging my Rust application?&lt;/p&gt;— (@jvmncs) &lt;a href=&quot;https://twitter.com/jvmncs/status/1927120951918891508&quot;&gt;January 21, 2025&lt;/a&gt;&lt;/blockquote&gt;

&lt;p&gt;This tweet shows a common problem in Nix: “Should I use crate2nix, cargo2nix, or naersk for packaging my Rust application?”&lt;/p&gt;
&lt;p&gt;devenv solved this for development environments differently: instead of making developers package everything with Nix, we provide tools through a simple &lt;code dir=&quot;auto&quot;&gt;languages.rust.enable&lt;/code&gt;. You get &lt;code dir=&quot;auto&quot;&gt;cargo&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;rustc&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;rust-analyzer&lt;/code&gt; in your shell without understanding Nix packaging.&lt;/p&gt;
&lt;p&gt;But when you’re ready to deploy, you face the same problem: which lang2nix tool should you use? Developers don’t want to compare &lt;code dir=&quot;auto&quot;&gt;crate2nix&lt;/code&gt; vs &lt;code dir=&quot;auto&quot;&gt;cargo2nix&lt;/code&gt; vs &lt;code dir=&quot;auto&quot;&gt;naersk&lt;/code&gt; vs &lt;code dir=&quot;auto&quot;&gt;crane&lt;/code&gt;—they want a tested solution that works.&lt;/p&gt;
&lt;p&gt;devenv now provides &lt;code dir=&quot;auto&quot;&gt;languages.rust.import&lt;/code&gt;, which packages Rust applications using &lt;a href=&quot;https://github.com/nix-community/crate2nix&quot;&gt;crate2nix&lt;/a&gt;. We evaluated the available tools and chose crate2nix, so you don’t have to.&lt;/p&gt;
&lt;p&gt;We’ve done this before. In &lt;a href=&quot;https://github.com/cachix/devenv/pull/1500&quot;&gt;PR #1500&lt;/a&gt;, we replaced &lt;a href=&quot;https://github.com/nix-community/fenix&quot;&gt;fenix&lt;/a&gt; with &lt;a href=&quot;https://github.com/oxalica/rust-overlay&quot;&gt;rust-overlay&lt;/a&gt; for Rust toolchains because rust-overlay was better maintained. Users didn’t need to change anything—devenv handled the transition while keeping the same &lt;code dir=&quot;auto&quot;&gt;languages.rust.enable = true&lt;/code&gt; interface.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;one-interface-for-all-languages&quot;&gt;One Interface for All Languages&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The typical workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Development&lt;/strong&gt;: Enable the language (&lt;code dir=&quot;auto&quot;&gt;languages.rust.enable = true&lt;/code&gt;) to get tools like &lt;code dir=&quot;auto&quot;&gt;cargo&lt;/code&gt;, &lt;code dir=&quot;auto&quot;&gt;rustc&lt;/code&gt;, and &lt;code dir=&quot;auto&quot;&gt;rust-analyzer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Packaging&lt;/strong&gt;: When ready to deploy, use &lt;code dir=&quot;auto&quot;&gt;languages.rust.import&lt;/code&gt; to package with Nix.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The same pattern works for all languages:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# https://devenv.sh/languages&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;python&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;go&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# https://devenv.sh/outputs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;outputs&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;rust-app&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;./rust-app&lt;/span&gt;&lt;span&gt; {};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;python-app&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;python&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;./python-app&lt;/span&gt;&lt;span&gt; {};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;go-app&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;go&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;./go-app&lt;/span&gt;&lt;span&gt; {};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;starting-with-rust&quot;&gt;Starting with Rust&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;languages.rust.import&lt;/code&gt; automatically generates Nix expressions from &lt;code dir=&quot;auto&quot;&gt;Cargo.toml&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;Cargo.lock&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Add the crate2nix input:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;inputs&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;add&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;crate2nix&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;github:nix-community/crate2nix&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--follows&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;nixpkgs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Import your Rust application:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;let&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# ./app is the directory containing your Rust project&apos;s Cargo.toml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;myapp&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;./app&lt;/span&gt;&lt;span&gt; {};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;in&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# Provide developer environment&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# Expose our application inside the environment&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;packages&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;myapp&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# https://devenv.sh/outputs&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;outputs&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;inherit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;myapp&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Build your application:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;outputs.myapp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;other-languages&quot;&gt;Other Languages&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;This API extends to other languages, each using the best packaging tool:&lt;/p&gt;
&lt;p&gt;We’ve also started using &lt;a href=&quot;https://github.com/pyproject-nix/uv2nix&quot;&gt;uv2nix&lt;/a&gt; to provide a similar interface for Python in &lt;a href=&quot;https://github.com/cachix/devenv/pull/2115&quot;&gt;PR #2115&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;thats-it&quot;&gt;That’s it&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;For feedback, join our &lt;a href=&quot;https://discord.gg/naMgvexb6q&quot;&gt;Discord community&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>devenv devlog: Processes are now tasks</title><link>https://devenv.sh/blog/2025/07/25/devenv-devlog-processes-are-now-tasks/</link><guid isPermaLink="true">https://devenv.sh/blog/2025/07/25/devenv-devlog-processes-are-now-tasks/</guid><pubDate>Fri, 25 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Building on the &lt;a href=&quot;https://devenv.sh/tasks/&quot;&gt;task runner&lt;/a&gt;, devenv now exposes all processes as tasks named &lt;code dir=&quot;auto&quot;&gt;devenv:processes:&amp;#x3C;name&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now you can run tasks before or after a process runs - addressing a &lt;a href=&quot;https://github.com/cachix/devenv/issues/1471&quot;&gt;frequently requested feature&lt;/a&gt; for orchestrating the startup sequence.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;execute-setup-tasks-before-the-process-starts&quot;&gt;Execute setup tasks before the process starts&lt;/h3&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;backend&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;cargo run --release&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&quot;db:migrate&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;diesel migration run&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;before&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;devenv:processes:backend&quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;When you run &lt;code dir=&quot;auto&quot;&gt;devenv up&lt;/code&gt; or the individual process task, migrations run first.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;run-cleanup-after-the-process-stops&quot;&gt;Run cleanup after the process stops&lt;/h3&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;node server.js&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&quot;app:cleanup&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;rm -f ./server.pid&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;rm -rf ./tmp/*&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;after&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;devenv:processes:app&quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;implementation&quot;&gt;Implementation&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Under the hood, process-compose now runs processes through &lt;code dir=&quot;auto&quot;&gt;devenv-tasks run --mode all devenv:processes:&amp;#x3C;name&gt;&lt;/code&gt; instead of executing them directly. This preserves all existing process functionality while adding task capabilities.&lt;/p&gt;
&lt;p&gt;The &lt;code dir=&quot;auto&quot;&gt;--mode all&lt;/code&gt; flag ensures that both &lt;code dir=&quot;auto&quot;&gt;before&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;after&lt;/code&gt; tasks are executed, maintaining the expected lifecycle behavior.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Future work on process dependencies (&lt;a href=&quot;https://github.com/cachix/devenv/issues/2037&quot;&gt;#2037&lt;/a&gt;) will also address native health check support (&lt;a href=&quot;https://github.com/F1bonacc1/process-compose/issues/371&quot;&gt;process-compose#371&lt;/a&gt;), eliminating the need for manual polling scripts.&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>devenv 1.8: Progress TUI, SecretSpec Integration, Listing Tasks, and Smaller Containers</title><link>https://devenv.sh/blog/2025/07/22/devenv-18-progress-tui-secretspec-integration-listing-tasks-and-smaller-containers/</link><guid isPermaLink="true">https://devenv.sh/blog/2025/07/22/devenv-18-progress-tui-secretspec-integration-listing-tasks-and-smaller-containers/</guid><pubDate>Tue, 22 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v1.8&quot;&gt;devenv 1.8&lt;/a&gt; fixes a couple of &lt;del&gt;annoying&lt;/del&gt; regressions since the 1.7 release, but also includes several new features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#progress-tui&quot;&gt;Progress TUI&lt;/a&gt; with async core&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#secretspec-integration&quot;&gt;SecretSpec integration&lt;/a&gt; for declarative secrets management&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#task-improvements&quot;&gt;Task improvements&lt;/a&gt; with task listing&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#cli-improvements&quot;&gt;CLI improvements&lt;/a&gt; with package options support&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#container-optimizations&quot;&gt;Smaller containers&lt;/a&gt; with 67% smaller images&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;progress-tui&quot;&gt;Progress TUI&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;We’ve rewritten our &lt;a href=&quot;https://github.com/cachix/devenv/pull/1969&quot;&gt;tracing integration&lt;/a&gt; to improve reporting on what devenv is doing.&lt;/p&gt;
&lt;p&gt;More importantly, devenv is now &lt;a href=&quot;https://github.com/cachix/devenv/pull/1970&quot;&gt;fully asynchronous under the hood&lt;/a&gt;, enabling parallel execution of operations. This means faster performance in scenarios where multiple independent tasks can run simultaneously.&lt;/p&gt;
&lt;p&gt;The new progress interface provides real-time feedback on what devenv is doing:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://devenv.sh/assets/images/devenv-progress-bar.gif&quot; alt=&quot;devenv progress bar&quot;&gt;&lt;/p&gt;
&lt;p&gt;We’re continuing to improve visibility into Nix operations to give you even better insights into the build process.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;secretspec-integration&quot;&gt;SecretSpec Integration&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;We’ve integrated &lt;a href=&quot;https://secretspec.dev&quot;&gt;SecretSpec&lt;/a&gt;, a new standard for declarative secrets management that separates secret declaration from provisioning.&lt;/p&gt;
&lt;p&gt;This allows teams to define what secrets applications need while letting each developer, CI system, and production environment provide them from their preferred secure provider.&lt;/p&gt;
&lt;p&gt;Learn more in &lt;a href=&quot;https://devenv.sh/blog/2025/07/21/announcing-secretspec-declarative-secrets-management/&quot;&gt;Announcing SecretSpec Declarative Secrets Management&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;task-improvements&quot;&gt;Task improvements&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;listing-tasks&quot;&gt;Listing tasks&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code dir=&quot;auto&quot;&gt;devenv tasks list&lt;/code&gt; command now groups tasks by namespace, providing a cleaner and more organized view:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;backend:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;└──&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lint&lt;/span&gt;&lt;span&gt; (has &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;check&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;└──&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;└──&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt; (watches: &lt;/span&gt;&lt;span&gt;src/backend/**/*.py&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;deploy:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;└──&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;production&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;docs:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;└──&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;generate&lt;/span&gt;&lt;span&gt; (watches: &lt;/span&gt;&lt;span&gt;docs/**/*.md&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;└──&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;publish&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;frontend:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;└──&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lint&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;└──&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt; (has &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;check&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;└──&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;running-multi-level-tasks&quot;&gt;Running multi-level tasks&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;You can now run tasks at any level in the hierarchy. By default, tasks run in single mode (only the specified task):&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Run only frontend:build (default single mode)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;frontend:build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Running&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt;     &lt;/span&gt;&lt;span&gt;frontend:build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Succeeded&lt;/span&gt;&lt;span&gt;         &lt;/span&gt;&lt;span&gt;frontend:build&lt;/span&gt;&lt;span&gt;                           &lt;/span&gt;&lt;span&gt;5ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Succeeded&lt;/span&gt;&lt;span&gt;                         &lt;/span&gt;&lt;span&gt;5.75ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Run frontend:build with all its dependencies (before mode)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;frontend:build&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--mode&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;before&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Running&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt;     &lt;/span&gt;&lt;span&gt;frontend:build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Succeeded&lt;/span&gt;&lt;span&gt;         &lt;/span&gt;&lt;span&gt;frontend:lint&lt;/span&gt;&lt;span&gt;                            &lt;/span&gt;&lt;span&gt;4ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Succeeded&lt;/span&gt;&lt;span&gt;         &lt;/span&gt;&lt;span&gt;frontend:test&lt;/span&gt;&lt;span&gt;                            &lt;/span&gt;&lt;span&gt;10ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Succeeded&lt;/span&gt;&lt;span&gt;         &lt;/span&gt;&lt;span&gt;frontend:build&lt;/span&gt;&lt;span&gt;                           &lt;/span&gt;&lt;span&gt;4ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Succeeded&lt;/span&gt;&lt;span&gt;                         &lt;/span&gt;&lt;span&gt;20.36ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Run frontend:build and all tasks that depend on it (after mode)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;frontend:build&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--mode&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;after&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Running&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt;     &lt;/span&gt;&lt;span&gt;frontend:build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Succeeded&lt;/span&gt;&lt;span&gt;         &lt;/span&gt;&lt;span&gt;frontend:build&lt;/span&gt;&lt;span&gt;                           &lt;/span&gt;&lt;span&gt;5ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;Succeeded&lt;/span&gt;&lt;span&gt;         &lt;/span&gt;&lt;span&gt;deploy:production&lt;/span&gt;&lt;span&gt;                        &lt;/span&gt;&lt;span&gt;5ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Succeeded&lt;/span&gt;&lt;span&gt;                         &lt;/span&gt;&lt;span&gt;11.44ms&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;cli-improvements&quot;&gt;CLI improvements&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;package-options-support&quot;&gt;Package options support&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;The CLI now supports specifying single packages via the &lt;code dir=&quot;auto&quot;&gt;--option&lt;/code&gt; flag (&lt;a href=&quot;https://github.com/cachix/devenv/pull/1988&quot;&gt;#1988&lt;/a&gt;). This allows for more flexible package configuration directly from the command line:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--option&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;languages.java.jdk.package:pkg&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;graalvm-oracle&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;container-optimizations&quot;&gt;Container optimizations&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The CI container &lt;a href=&quot;https://ghcr.io/cachix/devenv/devenv:v1.8&quot;&gt;ghcr.io/cachix/devenv/devenv:v1.8&lt;/a&gt; has been reduced (uncompressed) from 1,278 MB in v1.7 to 414 MB in v1.8—that’s a reduction of over 860 MB (67% smaller!).&lt;/p&gt;
&lt;p&gt;This makes &lt;a href=&quot;https://devenv.sh/integrations/devenv-container/&quot;&gt;devenv container&lt;/a&gt; much faster to pull and more efficient in CI/CD pipelines.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;thank-you&quot;&gt;Thank You&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Join our &lt;a href=&quot;https://discord.gg/naMgQehY&quot;&gt;Discord community&lt;/a&gt; to share your experiences and help shape devenv’s future!&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>Announcing SecretSpec: Declarative Secrets Management</title><link>https://devenv.sh/blog/2025/07/21/announcing-secretspec-declarative-secrets-management/</link><guid isPermaLink="true">https://devenv.sh/blog/2025/07/21/announcing-secretspec-declarative-secrets-management/</guid><pubDate>Mon, 21 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We’ve supported &lt;a href=&quot;https://devenv.sh/integrations/dotenv/&quot;&gt;.env integration&lt;/a&gt; for managing secrets, but it has several issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Apps are disconnected from their secrets&lt;/strong&gt; - applications lack a clear contract about which secrets they need&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parsing &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; is unclear&lt;/strong&gt; - comments, multiline values, and special characters all have ambiguous behavior across different parsers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Password manager integration is difficult&lt;/strong&gt; - requiring manual copy-paste or template workarounds&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vendor lock-in&lt;/strong&gt; - applications use custom parsing logic, making it hard to switch providers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No encryption&lt;/strong&gt; - &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; files are stored as plain text, vulnerable to accidental commits or unauthorized access&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While we could recommend solutions like &lt;a href=&quot;https://dotenvx.com/&quot;&gt;dotenvx&lt;/a&gt; to encrypt &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; files or &lt;a href=&quot;https://github.com/getsops/sops&quot;&gt;sops&lt;/a&gt; for general secret encryption, these bring new challenges:&lt;/p&gt;
&lt;blockquote align=&quot;center&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Don&apos;t you feel some anxiety given we&apos;ve normalized committing encrypted secrets to git repos?&lt;/p&gt;— Domen Kožar (@domenkozar) &lt;a href=&quot;https://twitter.com/domenkozar/status/1946244199663161712?ref_src=twsrc%5Etfw&quot;&gt;July 18, 2025&lt;/a&gt;&lt;/blockquote&gt; 
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single key management&lt;/strong&gt; - requires distributing and managing a master key&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trust requirements&lt;/strong&gt; - everyone with the key can decrypt all secrets&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rotation complexity&lt;/strong&gt; - departing team members require key rotation and re-encrypting all secrets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Larger teams often adopt solutions like &lt;a href=&quot;https://openbao.org/&quot;&gt;OpenBao&lt;/a&gt; (the open source fork of HashiCorp Vault), requiring significant infrastructure and operational overhead. Smaller teams face a gap between simple &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; files and complex enterprise solutions.&lt;/p&gt;
&lt;p&gt;What if instead of choosing one tool, we declared secrets uniformly and let each environment use its best provider?&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-hidden-problem-conflating-three-concerns&quot;&gt;The Hidden Problem: Conflating Three Concerns&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;We’ve created &lt;a href=&quot;https://secretspec.dev&quot;&gt;SecretSpec&lt;/a&gt; and integrated it into devenv. SecretSpec separates secret management into three distinct concerns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;WHAT&lt;/strong&gt; - Which secrets does your application need? (DATABASE_URL, API_KEY)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HOW&lt;/strong&gt; - Requirements (required vs optional, defaults, validation, environment)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WHERE&lt;/strong&gt; - Where are these secrets stored? (environment variables, Vault, AWS Secrets Manager)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By separating these concerns, your &lt;a href=&quot;https://secretspec.dev/concepts/declarative/&quot;&gt;application declares what secrets it needs&lt;/a&gt; in a simple TOML file. Each &lt;a href=&quot;https://secretspec.dev/concepts/profiles/&quot;&gt;developer, CI system, and production environment&lt;/a&gt; can provide those secrets from their &lt;a href=&quot;https://secretspec.dev/concepts/providers/&quot;&gt;preferred secure storage&lt;/a&gt; - &lt;strong&gt;without changing any application code&lt;/strong&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;one-spec-multiple-environments-different-providers&quot;&gt;One Spec, Multiple Environments, Different Providers&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Imagine you commit a &lt;code dir=&quot;auto&quot;&gt;secretspec.toml&lt;/code&gt; file that declares:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# secretspec.toml - committed to your repo&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[project]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;name = &lt;/span&gt;&lt;span&gt;&quot;my-app&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;revision = &lt;/span&gt;&lt;span&gt;&quot;1.0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[profiles.default]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;DATABASE_URL = { description = &lt;/span&gt;&lt;span&gt;&quot;PostgreSQL connection string&quot;&lt;/span&gt;&lt;span&gt;, required = &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;REDIS_URL = { description = &lt;/span&gt;&lt;span&gt;&quot;Redis connection string&quot;&lt;/span&gt;&lt;span&gt;, required = &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;STRIPE_API_KEY = { description = &lt;/span&gt;&lt;span&gt;&quot;Stripe API key&quot;&lt;/span&gt;&lt;span&gt;, required = &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[profiles.development]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Inherits from default profile - only override what changes&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;DATABASE_URL = { default = &lt;/span&gt;&lt;span&gt;&quot;postgresql://localhost/myapp_dev&quot;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;REDIS_URL = { default = &lt;/span&gt;&lt;span&gt;&quot;redis://localhost:6379&quot;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;STRIPE_API_KEY = { description = &lt;/span&gt;&lt;span&gt;&quot;Stripe API key (test mode)&quot;&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[profiles.production]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Production keeps strict requirements from default profile&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Now, here’s the magic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You&lt;/strong&gt; (on macOS): Store it in Keychain, retrieve with &lt;code dir=&quot;auto&quot;&gt;secretspec --provider keyring run -- cmd args&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Your teammate&lt;/strong&gt; (on Linux): Store it in GNOME Keyring, same command works&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;That one developer&lt;/strong&gt;: Still uses a &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; file locally (we don’t judge, we’ve been there)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI/CD&lt;/strong&gt;: Reads from environment variables in GitHub Actions &lt;code dir=&quot;auto&quot;&gt;secretspec --provider env run -- cmd args&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Production&lt;/strong&gt;: Secrets get provisioned using AWS Secret Manager&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Same specification. Different providers. Zero code changes.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;example-one-spec-three-environments&quot;&gt;Example: One Spec, Three Environments&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Let’s walk through migrating from &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; to SecretSpec.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;setting-up-secretspec-for-development&quot;&gt;Setting up secretspec for development&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;First, choose your default provider and profile:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; Select your preferred provider backend:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; keyring: Uses system keychain (&lt;/span&gt;&lt;span&gt;Recommended&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;onepassword:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;OnePassword&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;manager&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;dotenv:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Traditional&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;.env&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;files&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;env:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Read-only&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;environment&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;variables&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;lastpass:&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;LastPass&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;password&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;manager&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; Select your default profile:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&gt;&lt;/span&gt;&lt;span&gt; development&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;default&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;none&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Configuration&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;saved&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;to&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;~/.config/secretspec/config.toml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;importing-secrets&quot;&gt;Importing secrets&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Create &lt;code dir=&quot;auto&quot;&gt;secretspec.toml&lt;/code&gt; from your existing &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;init&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--from&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;dotenv&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;1-local-development-with-devenv-youre-on-macos&quot;&gt;1. Local Development with devenv (You’re on macOS)&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Enable SecretSpec in &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;minio&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;buckets&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;secrets&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;BUCKET_NAME&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Start the minio process:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;up&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;✓&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Starting&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;minio...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;2-cicd-github-actions&quot;&gt;2. CI/CD (GitHub Actions)&lt;/h3&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;.github/workflows/test.yml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;Run tests&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;env&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;DATABASE_URL&lt;/span&gt;&lt;span&gt;: {{ &lt;/span&gt;&lt;span&gt;secrets.TEST_DATABASE_URL&lt;/span&gt;&lt;span&gt; }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;STRIPE_API_KEY&lt;/span&gt;&lt;span&gt;: {{ &lt;/span&gt;&lt;span&gt;secrets.STRIPE_TEST_KEY&lt;/span&gt;&lt;span&gt; }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;secretspec run --provider env --profile production -- npm test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;3-production-flyio&quot;&gt;3. Production (Fly.io)&lt;/h3&gt;&lt;/div&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;fly.toml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[processes]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;web = &lt;/span&gt;&lt;span&gt;&quot;secretspec run --provider env --profile production -- npm start&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Set secrets using fly CLI:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# fly secrets set DATABASE_URL=postgresql://... STRIPE_API_KEY=sk_live_...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# SecretSpec will read these from environment variables&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Notice what didn’t change?&lt;/strong&gt; Your &lt;code dir=&quot;auto&quot;&gt;secretspec.toml&lt;/code&gt;. Same specification, different providers, zero code changes.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;loading-secrets-in-your-application&quot;&gt;Loading secrets in your application&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;While &lt;code dir=&quot;auto&quot;&gt;secretspec run&lt;/code&gt; provides secrets as environment variables, your application remains disconnected from knowing which secrets it requires. The Rust SDK bridges this gap by providing type-safe access to your declared secrets.&lt;/p&gt;
&lt;p&gt;The Rust SDK provides compile-time guarantees:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;// Generate typed structs from secretspec.toml&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;secretspec_derive&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;declare_secrets!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;secretspec.toml&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;fn&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;main&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;-&gt;&lt;/span&gt;&lt;span&gt; Result&amp;#x3C;(), Box&amp;#x3C;&lt;/span&gt;&lt;span&gt;dyn&lt;/span&gt;&lt;span&gt; std&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;error&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;Error&gt;&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// Load secrets using the builder pattern&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; secretspec &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SecretSpec&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;builder&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;with_provider&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;keyring&quot;&lt;/span&gt;&lt;span&gt;)  &lt;/span&gt;&lt;span&gt;// Can use provider name or URI like &quot;dotenv:/path/to/.env&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;with_profile&lt;/span&gt;&lt;span&gt;(Profile&lt;/span&gt;&lt;span&gt;::&lt;/span&gt;&lt;span&gt;Production)  &lt;/span&gt;&lt;span&gt;// Can use string or Profile enum&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;load&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// Access secrets (field names are lowercased)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Database: {}&quot;&lt;/span&gt;&lt;span&gt;, secretspec&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;secrets&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;database_url);  &lt;/span&gt;&lt;span&gt;// DATABASE_URL → database_url&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Stripe: {}&quot;&lt;/span&gt;&lt;span&gt;, secretspec&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;secrets&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stripe_api_key);  &lt;/span&gt;&lt;span&gt;// STRIPE_API_KEY → stripe_api_key&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// Optional secrets are Option&amp;#x3C;String&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; Some(redis) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;#x26;&lt;/span&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;secrets&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;redis_url {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Redis: {}&quot;&lt;/span&gt;&lt;span&gt;, redis);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// Access profile and provider information&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Using profile: {}&quot;&lt;/span&gt;&lt;span&gt;, secretspec&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;profile);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;println!&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Using provider: {}&quot;&lt;/span&gt;&lt;span&gt;, secretspec&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;provider);&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;// For backwards compatibility, export as environment variables&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;secretspec&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;secrets&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;set_as_env_vars&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;Ok(())&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Add to your &lt;code dir=&quot;auto&quot;&gt;Cargo.toml&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;[dependencies]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;secretspec = &lt;/span&gt;&lt;span&gt;&quot;0.2.0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;secretspec_derive = &lt;/span&gt;&lt;span&gt;&quot;0.2.0&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;The application code never specifies &lt;em&gt;where&lt;/em&gt; to get secrets - only &lt;em&gt;what&lt;/em&gt; it needs through the TOML file. This keeps your application logic clean and portable.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;building-sdks-for-other-languages&quot;&gt;Building SDKs for Other Languages&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;We’d love to see more SDKs that bring this same declarative approach to Python, JavaScript, Go, and other languages.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;a-world-of-possibilities&quot;&gt;A world of possibilities&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;We’re exploring features for future workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cachix/secretspec/issues/11&quot;&gt;Secret rotation without shutting down the application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cachix/secretspec/issues/9&quot;&gt;Generating secrets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cachix/secretspec/issues/10&quot;&gt;Mixing providers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;final-words&quot;&gt;Final words&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Let’s make secret management as declarative as package management. Let’s stop sharing &lt;code dir=&quot;auto&quot;&gt;.env&lt;/code&gt; files over Slack. Let’s build better tools for developers.&lt;/p&gt;
&lt;p&gt;Share your thoughts on our &lt;a href=&quot;https://discord.gg/naMgQehY&quot;&gt;Discord community&lt;/a&gt; or &lt;a href=&quot;https://github.com/cachix/secretspec/issues&quot;&gt;open an issue on GitHub&lt;/a&gt;. We’d love to hear how you handle secrets in your team.&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>devenv 1.7: CUDA Support, Enhanced Tasks, and MCP support</title><link>https://devenv.sh/blog/2025/07/03/devenv-17-cuda-support-enhanced-tasks-and-mcp-support/</link><guid isPermaLink="true">https://devenv.sh/blog/2025/07/03/devenv-17-cuda-support-enhanced-tasks-and-mcp-support/</guid><pubDate>Thu, 03 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v1.7&quot;&gt;devenv 1.7&lt;/a&gt; brings several practical improvements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#platform-specific-configuration&quot;&gt;CUDA support&lt;/a&gt; that works across platforms&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#model-context-protocol-mcp-support&quot;&gt;MCP support&lt;/a&gt; that understands devenv configurations&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#tasks-enhancements&quot;&gt;Tasks that only run when their inputs change&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#progress-on-snix-support&quot;&gt;Groundwork for Snix&lt;/a&gt;, Rust-based Nix implementation&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;progress-on-snix-support&quot;&gt;Progress on Snix Support&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;We’ve started work on supporting multiple Nix implementations in devenv. The codebase now includes a backend abstraction layer that will allow users to choose between different Nix implementations.&lt;/p&gt;
&lt;p&gt;This architectural change paves the way for integrating &lt;a href=&quot;https://github.com/cachix/snix&quot;&gt;Snix (our development fork)&lt;/a&gt;. While the Snix backend isn’t functional yet, the groundwork is in place for building out this Rust-based reimplementation to the C++ Nix implementation. See &lt;a href=&quot;https://github.com/cachix/devenv/pull/1950&quot;&gt;PR #1950&lt;/a&gt; for implementation details.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;platform-specific-configuration&quot;&gt;Platform-Specific Configuration&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Here’s how to enable CUDA support only on Linux systems while keeping your environment working smoothly on macOS:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CUDA-enabled packages are built with GPU support on Linux&lt;/li&gt;
&lt;li&gt;macOS developers can still work on the same project without CUDA&lt;/li&gt;
&lt;li&gt;The correct CUDA capabilities are set for your target GPUs&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.yaml&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;nixpkgs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;allowUnfree&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;x86_64-linux&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;cudaSupport&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;cudaCapabilities&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;&quot;7.5&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;8.6&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&quot;8.9&quot;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;tasks-enhancements&quot;&gt;Tasks Enhancements&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Tasks now skip execution when their input files haven’t changed, using the new &lt;code dir=&quot;auto&quot;&gt;execIfModified&lt;/code&gt; option:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;frontend:build&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;npm run build&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;execIfModified&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;src/**/*.tsx&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;src/**/*.css&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;package.json&quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;backend:compile&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;cargo build --release&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;execIfModified&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;src/**/*.rs&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Cargo.toml&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;Cargo.lock&quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This dramatically speeds up incremental builds by skipping unnecessary work.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;namespace-based-task-execution&quot;&gt;Namespace-Based Task Execution&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Run all tasks within a namespace using prefix matching:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Run all frontend tasks&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;frontend&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;model-context-protocol-mcp-support&quot;&gt;Model Context Protocol (MCP) Support&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;devenv now includes a built-in MCP server that enables AI assistants like Claude to better understand and generate devenv configurations:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;# Start the MCP server&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;mcp&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;AI assistants can now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Search for packages and their options&lt;/li&gt;
&lt;li&gt;Understand devenv’s configuration format&lt;/li&gt;
&lt;li&gt;Generate valid configurations based on your requirements&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;quality-of-life-improvements&quot;&gt;Quality of Life Improvements&lt;/h2&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Shell Integration&lt;/strong&gt;: Your shell aliases and functions now work correctly&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clean Mode&lt;/strong&gt;: Fixed shell corruption when using &lt;code dir=&quot;auto&quot;&gt;--clean&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Messages&lt;/strong&gt;: More helpful error messages when commands fail&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;State Handling&lt;/strong&gt;: Automatically recovers from corrupted cache files&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Direnv Integration&lt;/strong&gt;: Fewer unnecessary environment reloads&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;upcoming-18-release&quot;&gt;Upcoming 1.8 Release&lt;/h2&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;standardized-language-tooling-configuration&quot;&gt;Standardized Language Tooling Configuration&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;All language modules will support the same configuration pattern (&lt;a href=&quot;https://github.com/cachix/devenv/pull/1974&quot;&gt;PR #1974&lt;/a&gt;):&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;dev&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;lsp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;debugger&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;linter&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;formatter&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;false&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;rust-import-functionality&quot;&gt;Rust Import Functionality&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Import Rust projects and their dependencies as Nix packages with the new &lt;code dir=&quot;auto&quot;&gt;languages.rust.import&lt;/code&gt; configuration (&lt;a href=&quot;https://github.com/cachix/devenv/pull/1946&quot;&gt;PR #1946&lt;/a&gt;):&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;mypackage&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;root&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;./.&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;packages&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;mypackage&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;packages&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;That allows us to bridge the gap between developer environments and fully packaged Rust applications using Nix.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;async-core&quot;&gt;Async Core&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;Operations that can run in parallel will (&lt;a href=&quot;https://github.com/cachix/devenv/pull/1970&quot;&gt;PR #1970&lt;/a&gt;).&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Join our &lt;a href=&quot;https://discord.gg/naMgQehY&quot;&gt;Discord community&lt;/a&gt; to share your experiences and help shape devenv’s future.&lt;/p&gt;
&lt;p&gt;We’re particularly interested in feedback on the standardized language tooling configuration coming in 1.8 - let us know if this approach works for your use cases!&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>devenv 1.6: Extensible Ad-Hoc Nix Environments</title><link>https://devenv.sh/blog/2025/04/25/devenv-16-extensible-ad-hoc-nix-environments/</link><guid isPermaLink="true">https://devenv.sh/blog/2025/04/25/devenv-16-extensible-ad-hoc-nix-environments/</guid><pubDate>Fri, 25 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;devenv 1.6 &lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v1.6&quot;&gt;has been tagged&lt;/a&gt;, allowing you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create temporary environments directly from the command line without requiring a &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Temporarily modify existing environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;create-environments-on-the-fly&quot;&gt;Create Environments on the Fly&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Developer environments on demand using the new &lt;code dir=&quot;auto&quot;&gt;--option&lt;/code&gt; (&lt;code dir=&quot;auto&quot;&gt;-O&lt;/code&gt;) flag:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--option&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;languages.python.enable:bool&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;         &lt;/span&gt;&lt;span&gt;--option&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;packages:pkgs&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;ncdu git ripgrep&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;\&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;         &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This command creates a temporary Python environment without writing any configuration files.&lt;/p&gt;
&lt;p&gt;Ad-hoc environments are ideal for quickly testing languages or tools without committing to a full project setup:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-O&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;languages.elixir.enable:bool&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;shell&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;iex&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;supported-option-types&quot;&gt;Supported Option Types&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code dir=&quot;auto&quot;&gt;--option&lt;/code&gt; flag supports multiple data types, making it flexible for various use cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;:string&lt;/code&gt; for text values&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;:int&lt;/code&gt; for integers&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;:float&lt;/code&gt; for decimal numbers&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;:bool&lt;/code&gt; for true/false values&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;:path&lt;/code&gt; for file paths&lt;/li&gt;
&lt;li&gt;&lt;code dir=&quot;auto&quot;&gt;:pkgs&lt;/code&gt; for specifying Nix packages&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;github-actions-with-matrices&quot;&gt;GitHub Actions with Matrices&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;One of the most powerful applications of ad-hoc environments is in CI pipelines, where you can easily implement testing matrices across different configurations:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;jobs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;strategy&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;matrix&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;python-version&lt;/span&gt;&lt;span&gt;: [&lt;/span&gt;&lt;span&gt;&apos;3.9&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;3.10&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&apos;3.11&apos;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;steps&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;uses&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;actions/checkout@v3&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;uses&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;cachix/install-nix-action@v31&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;uses&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;cachix/cachix-action@v16&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;with&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;          &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;Install devenv.sh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;nix profile install nixpkgs#devenv&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;name&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;Test with Python {{ &apos;${{ matrix.python-version }}&apos; }}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;run&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;devenv --option languages.python.enable:bool true \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                 &lt;/span&gt;&lt;/span&gt;&lt;span&gt;--option languages.python.version:string {{ &apos;${{ matrix.python-version }}&apos; }} \&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;                 &lt;/span&gt;&lt;/span&gt;&lt;span&gt;test&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This approach lets you validate your code across multiple language versions or dependency combinations without maintaining separate configuration files for each scenario.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;combining-with-existing-configurations&quot;&gt;Combining with Existing Configurations&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;When used with an existing &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; file, &lt;code dir=&quot;auto&quot;&gt;--option&lt;/code&gt; values override the configuration settings in the file, making it easy to temporarily modify your environment.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;switching-between-environment-profiles&quot;&gt;Switching Between Environment Profiles&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Ad-hoc options are perfect for switching between predefined profiles in your development environment:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--option&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;profile:string&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;backend&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;up&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This enables you to switch between frontend, backend, or other custom profiles without modifying your configuration files.&lt;/p&gt;
&lt;p&gt;See our &lt;a href=&quot;https://devenv.sh/profiles/&quot;&gt;Profiles guide&lt;/a&gt; for more details on setting up and using profiles.&lt;/p&gt;
&lt;p&gt;For complete documentation on this feature, visit our &lt;a href=&quot;https://devenv.sh/ad-hoc-developer-environments/&quot;&gt;Ad-hoc Developer Environments guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We’re excited to see how you’ll use ad-hoc environments to streamline your development workflow. Share your feedback on &lt;a href=&quot;https://github.com/cachix/devenv&quot;&gt;GitHub&lt;/a&gt; or &lt;a href=&quot;https://discord.gg/MycroftAI&quot;&gt;join our Discord community&lt;/a&gt;!&lt;/p&gt;
</content:encoded></item><item><title>devenv 1.5: Overlays Support and Performance Improvements</title><link>https://devenv.sh/blog/2025/04/13/devenv-15-overlays-support-and-performance-improvements/</link><guid isPermaLink="true">https://devenv.sh/blog/2025/04/13/devenv-15-overlays-support-and-performance-improvements/</guid><pubDate>Sun, 13 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this release, we’re introducing a powerful Nix concept: overlays for modifying and extending the nixpkgs package set, along with significant performance and TLS certificate improvements.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;overlays-customizing-your-package-set&quot;&gt;Overlays: Customizing Your Package Set&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Overlays allow you to modify or extend the default package set (&lt;code dir=&quot;auto&quot;&gt;pkgs&lt;/code&gt;) that devenv uses. This is particularly useful when you need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Apply patches to existing packages&lt;/li&gt;
&lt;li&gt;Use different versions of packages than what’s provided by default&lt;/li&gt;
&lt;li&gt;Add custom packages not available in nixpkgs&lt;/li&gt;
&lt;li&gt;Use packages from older nixpkgs versions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s an example of using overlays in your &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; file to apply a patch to the &lt;code dir=&quot;auto&quot;&gt;hello&lt;/code&gt; package:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# Define overlays to modify the package set&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;overlays&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;# Override an existing package with a patch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;prev&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;hello&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;prev&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;hello&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;overrideAttrs&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;oldAttrs&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;patches&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;oldAttrs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;patches&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;or&lt;/span&gt;&lt;span&gt; []) &lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;./hello-fix.patch&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;});&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# Use the modified packages&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;packages&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;hello&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;my-tool&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h3 id=&quot;using-packages-from-a-different-nixpkgs-version&quot;&gt;Using packages from a different nixpkgs version&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;You can even use packages from a different nixpkgs version by adding an extra input to your &lt;code dir=&quot;auto&quot;&gt;devenv.yaml&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;inputs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;nixpkgs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;github:cachix/devenv-nixpkgs/rolling&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;nixpkgs-unstable&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;url&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;github:nixos/nixpkgs/nixpkgs-unstable&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;And then using it in your &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;inputs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;overlays&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;prev&lt;/span&gt;&lt;span&gt;: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;nodejs&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;inputs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;nixpkgs-unstable&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;system&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;prev&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;stdenv&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;system&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;nodejs&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;})&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;# Now you can use the unstable version of Node.js&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;javascript&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;For more details and examples, check out the &lt;a href=&quot;https://devenv.sh/overlays/&quot;&gt;overlays documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;tls-improvements-native-system-certificates&quot;&gt;TLS Improvements: Native System Certificates&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;We’ve heard from ZScaler how &lt;a href=&quot;https://bsky.app/profile/jm2dev.bsky.social/post/3lle7mdguhs2j&quot;&gt;they are using devenv&lt;/a&gt; and we’ve fixed their major annoyance
by ensuring devenv now respects system certificates that many enterprises rely on.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;macos-development-enhancements-custom-apple-sdk-support&quot;&gt;macOS Development Enhancements: Custom Apple SDK Support&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;For macOS developers, we’ve added the ability to customize which Apple SDK is used for development:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;apple&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;sdk&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;apple-sdk_15&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This allows you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Control exactly which version of the SDK to use&lt;/li&gt;
&lt;li&gt;Ensure consistency across development environments&lt;/li&gt;
&lt;li&gt;Avoid incompatibilities between different macOS versions&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;performance-improvements&quot;&gt;Performance Improvements&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Sander further tweaked the &lt;a href=&quot;https://oceansprint.org/reports/2025/&quot;&gt;performance of developer environment activation at OceanSprint&lt;/a&gt; when it can be cached:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linux: ~500ms -&gt; ~150ms&lt;/li&gt;
&lt;li&gt;macOS: ~1300ms -&gt; ~300ms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Join our &lt;a href=&quot;https://discord.gg/naMgQehY&quot;&gt;Discord&lt;/a&gt; to share feedback and suggestions!&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>devenv 1.4: Generating Nix Developer Environments Using AI</title><link>https://devenv.sh/blog/2025/02/13/devenv-14-generating-nix-developer-environments-using-ai/</link><guid isPermaLink="true">https://devenv.sh/blog/2025/02/13/devenv-14-generating-nix-developer-environments-using-ai/</guid><pubDate>Thu, 13 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the main obstacles in using Nix for development environments is mastering the language itself.
It takes time to become proficient writing Nix.&lt;/p&gt;
&lt;p&gt;How about using AI to generate it instead:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$ devenv generate a Python project using Torch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;• Generating devenv.nix and devenv.yaml, this should take about a minute ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You can also use &lt;a href=&quot;http://devenv.new&quot;&gt;devenv.new&lt;/a&gt; to generate a new environment.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;generating-devenvnix-for-an-existing-project&quot;&gt;Generating devenv.nix for an existing project&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;You can also tell devenv to create a scaffold based on your existing git source code:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$ devenv generate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;• Generating devenv.nix and devenv.yaml, this should take about a minute ...&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;div&gt;&lt;h2 id=&quot;telemetry&quot;&gt;Telemetry&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;To continually enhance the AI’s recommendations, we collect anonymous data on the environments generated. This feedback helps us train better models and improve accuracy.&lt;/p&gt;
&lt;p&gt;Of course, your privacy matters—if you prefer not to participate, just add the &lt;code dir=&quot;auto&quot;&gt;--disable-telemetry&lt;/code&gt; flag when generating environments.
We also adhere to the &lt;a href=&quot;https://consoledonottrack.com/&quot;&gt;donottrack&lt;/a&gt; standard.&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>devenv is switching its Nix implementation to Tvix</title><link>https://devenv.sh/blog/2024/10/22/devenv-is-switching-its-nix-implementation-to-tvix/</link><guid isPermaLink="true">https://devenv.sh/blog/2024/10/22/devenv-is-switching-its-nix-implementation-to-tvix/</guid><pubDate>Tue, 22 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In February 2020, I went on a 16-day, 1200km moped trip across northern Thailand with a couple of friends.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://devenv.sh/assets/images/thailand.jpg&quot; width=&quot;300&quot; alt=&quot;Somewhere in northern Thailand&quot;&gt;
  &lt;figcaption&gt;Somewhere in northern Thailand near Pai.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As we drove for hours on end, I was listening to an audiobook fittingly called &lt;a href=&quot;https://www.goodreads.com/book/show/61329.Crossing_the_Chasm&quot;&gt;Crossing the Chasm&lt;/a&gt;.
The book explores the challenges faced by nacent technologies on their way to mainstream adoption.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://devenv.sh/assets/images/chasm.webp&quot; alt=&quot;Crossing the chasm&quot;&gt;
&lt;/figure&gt;
&lt;p&gt;In the years that followed, I couldn’t help noticing the disconnect between Nix’s devoted user base
and its apparent lack of widespread adoption in the broader tech community.&lt;/p&gt;
&lt;p&gt;Over 2021 and 2022, I focused my efforts and started &lt;a href=&quot;https://nix.dev&quot;&gt;nix.dev&lt;/a&gt;, a resource for practical and accessible Nix tutorials, thinking that good documentation was the thing holding Nix back.
Eventually, I came to the realization that improving documentation alone will only get us so far.&lt;/p&gt;
&lt;p&gt;We needed to fix the foundations.&lt;/p&gt;
&lt;p&gt;We needed to remove things to reduce the cognitive load when using Nix.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;the-negative-feedback-loop&quot;&gt;The negative feedback loop&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Over the years at &lt;a href=&quot;https://www.cachix.org&quot;&gt;Cachix&lt;/a&gt; we’ve talked to team after team
abandoning Nix and have observed a surprisingly consistent pattern.&lt;/p&gt;
&lt;p&gt;Nix is initially introduced by someone enthusiastic about the technology. Then, faced with
a steep adoption curve, it is abandoned after backlash from the rest of the team.&lt;/p&gt;
&lt;p&gt;Making it trivial for a project to adopt and maintain a development environment
is crucial for other team members to see the benefits of Nix.&lt;/p&gt;
&lt;p&gt;For example, &lt;a href=&quot;https://shopify.engineering/shipit-presents-how-shopify-uses-nix&quot;&gt;Shopify was vocal about Nix way back in 2020&lt;/a&gt;,
but eventually went quiet. Having companies like Shopify adopt Nix would be a major step forward for the whole ecosystem.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;an-interface-as-the-heart-of-the-developer-experience&quot;&gt;An interface as the heart of the Developer Experience&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Since the &lt;a href=&quot;https://devenv.sh/blog/2022/11/11/hello-world-devenv-01/&quot;&gt;0.1 release two years ago&lt;/a&gt;, we’ve been rapidly iterating on a declarative interface for
developer environments. We now have support for over &lt;a href=&quot;https://devenv.sh/languages/ansible/&quot;&gt;50 languages&lt;/a&gt; and &lt;a href=&quot;https://devenv.sh/services/adminer/&quot;&gt;30 services&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;packages&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cargo-watch&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rust&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;channel&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;nightly&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;rustflags&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;-Z threads=8&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;targets&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;wasm32-unknown-unknown&quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;processes&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;backend&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;cargo watch -x run&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;services&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;postgresql&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;With the introduction of &lt;a href=&quot;https://devenv.sh/blog/2024/09/24/devenv-12-tasks-for-convergent-configuration-with-nix/&quot;&gt;tasks in the 1.2 release&lt;/a&gt; and
&lt;a href=&quot;https://devenv.sh/blog/2024/10/03/devenv-13-instant-developer-environments-with-nix-caching/&quot;&gt;Nix caching in 1.3&lt;/a&gt;, we’re pretty happy with
the &lt;code dir=&quot;auto&quot;&gt;devenv&lt;/code&gt; command-line interface and the extensible nature of the module system.&lt;/p&gt;
&lt;p&gt;The modular architecture of the module system allows for seamless addition, modification, and removal of configuration options.
This flexibility extends to defining &lt;a href=&quot;https://devenv.sh/composing-using-imports/&quot;&gt;your own options&lt;/a&gt; for the software you’re writing.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;why-do-we-need-a-nix-rewrite&quot;&gt;Why do we need a Nix rewrite?&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;We’ve been using the &lt;strong&gt;Nix command-line interface under the hood as a low-level API&lt;/strong&gt; to
the evaluator and Nix store. We would’ve preferred to use something akin to an SDK instead, however
the command-line interface was the &lt;strong&gt;most sensible interface two years ago&lt;/strong&gt; out of the available options.&lt;/p&gt;
&lt;p&gt;The new C FFI (Foreign Function Interface) could potentially grow into a viable solution, but
it would necessitate substantial development effort and still leave us vulnerable to memory-safety
issues. Moreover, the architecture of the Nix codebase is structured more as a monolithic framework rather than a modular library.&lt;/p&gt;
&lt;p&gt;Ideally, if we’re committing to fixing the developer experience over the next years, we’d want to have Nix implemented as a library in Rust.&lt;/p&gt;
&lt;p&gt;Fortunately, such a project already exists and it’s called &lt;a href=&quot;https://tvix.dev&quot;&gt;Tvix&lt;/a&gt;. Started by &lt;a href=&quot;http://flokli.de/&quot;&gt;flokli&lt;/a&gt; and &lt;a href=&quot;https://github.com/tazjin&quot;&gt;tazjin&lt;/a&gt; in &lt;a href=&quot;https://tvl.fyi/blog/rewriting-nix&quot;&gt;“Rewriting Nix”&lt;/a&gt;,
Tvix is a re-implementation of Nix in Rust, offering both memory-safety and a library-oriented architecture with independently usable components. Leveraging Rust’s
abstractions and ecosystem (e.g. &lt;a href=&quot;https://tracing.rs/&quot;&gt;tracing.rs&lt;/a&gt;), Tvix is positioned to significantly enhance the developer experience for &lt;code dir=&quot;auto&quot;&gt;devenv&lt;/code&gt; developers and users.&lt;/p&gt;
&lt;p&gt;There are many architectural differences besides the obvious “Rewrite In Rust” cliche,
so we’ll talk about them as we start replacing our Nix command-line calls with Tvix libraries, starting with the evaluator.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;integrating-the-tvix-evaluator&quot;&gt;Integrating the Tvix evaluator&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;The Nix evaluator directly traverses the abstract syntax tree (AST) during evaluation, while Tvix uses a bytecode virtual machine crafted
according to the &lt;a href=&quot;https://craftinginterpreters.com/&quot;&gt;Crafting Interpreters&lt;/a&gt; book.&lt;/p&gt;
&lt;p&gt;Tvix compiles Nix code into compact bytecode, then executes it in a virtual machine. This two-step approach offers potential performance benefits and optimization opportunities,
like many other interpreted languages.&lt;/p&gt;
&lt;p&gt;When you re-evaluate &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt;, you’re most likely changing &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; and not one of the few dozen Nix files that come from the devenv repository,
or even the few thousand Nix files from the &lt;a href=&quot;https://github.com/NixOS/nixpkgs&quot;&gt;nixpkgs&lt;/a&gt; repository that could all be cached as bytecode.&lt;/p&gt;
&lt;p&gt;In order to integrate the Tvix evaluator with &lt;code dir=&quot;auto&quot;&gt;devenv&lt;/code&gt; we’ll need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Finish implementing &lt;a href=&quot;https://cl.tvl.fyi/c/depot/+/12379&quot;&gt;builtins.fetchTree&lt;/a&gt;, where we have some ideas on how to simplify the caching layer
and get rid of the annoying dependency on GitHub’s rate-limited api.github.com endpoint.&lt;/li&gt;
&lt;li&gt;Implement an evaluation debugger that will allow inspecting a program’s state in case of errors.&lt;/li&gt;
&lt;li&gt;Finish implementing &lt;a href=&quot;https://cl.tvl.fyi/c/depot/+/12416&quot;&gt;tvix-eval-jobs&lt;/a&gt; that will be used for regression tests against nixpkgs
to make sure that the evaluator behaves correctly.&lt;/li&gt;
&lt;li&gt;Create debug tooling for when we discover regressions in the evaluator.&lt;/li&gt;
&lt;li&gt;Integrate a nix-daemon layer to schedule builds.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also recently streamed a &lt;a href=&quot;https://www.youtube.com/watch?v=6FAxZDnsH5w&quot;&gt;Let’s explore the Tvix evaluator&lt;/a&gt; video for those interested in digging into the code.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;using-language-specific-package-managers-as-the-build-system&quot;&gt;Using language-specific package managers as the build system&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Once we’ve integrated the evaluator, we can finally generalize building languages using Nix reproducible builds
by running the underlying build system to generate Nix expressions:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;graph TD&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;A[devenv];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;A --&gt;|Rust| C[Cargo];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;A --&gt;|JavaScript| D[npm];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;A --&gt;|PHP| E[Composer];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;C --&gt;|Cargo.lock| F{Nix};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;D --&gt;|package.json| F{Nix};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;E --&gt;|composer.lock| F{Nix};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In &lt;a href=&quot;https://www.microsoft.com/en-us/research/uploads/prod/2018/03/build-systems.pdf&quot;&gt;Build Systems à la Carte&lt;/a&gt;,
Nix is labelled as a suspending task scheduler.&lt;/p&gt;
&lt;p&gt;In the general case, the dependency graph is computed statically, but a dependency can
declare its dependencies dynamically as part of the build by returning more Nix code.&lt;/p&gt;
&lt;p&gt;That’s when evaluation and build phases start to mix, with evaluation depending on the result of a build,
which is typically called import from derivation (as the naming comes from the implementation).&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;sequenceDiagram&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;autonumber&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;participant NixEvaluator as Nix evaluator&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;participant NixStore as Nix store&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;NixEvaluator-&gt;&gt;NixEvaluator: evaluate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;NixEvaluator-&gt;&gt;NixStore: write derivation&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;NixStore-&gt;&gt;NixStore: build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;NixStore-&gt;&gt;NixEvaluator: read derivation output&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;NixEvaluator-&gt;&gt;NixEvaluator: evaluate&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Since evaluation in Nix is single-threaded, the process described above gets blocked on each build requested during evaluation.&lt;/p&gt;
&lt;p&gt;Implementing parallel evaluation in Tvix, after we figure out the architectural details of how it should work, will unlock the ability to support automatic conversion
of language-specific build systems into Nix without sacrificing neither the developer experience, nor memory safety.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;final-words&quot;&gt;Final Words&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;As we embark on this new chapter with &lt;a href=&quot;https://tvix.dev&quot;&gt;Tvix&lt;/a&gt;, I’m reminded of the journey that brought us here.
It’s been a decade since I wrote the &lt;a href=&quot;https://domenkozar.com/2014/03/11/why-puppet-chef-ansible-arent-good-enough-and-we-can-do-better/&quot;&gt;we can do better&lt;/a&gt; blog post,
highlighting the potential for improvement in configuration management and development environments, and I’m glad to see it all finally coming together.&lt;/p&gt;
&lt;p&gt;Keep an eye out for updates and join the discussion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attend &lt;a href=&quot;https://talks.nixcon.org/nixcon-2024/talk/AM7K7F/&quot;&gt;“devenv is switching to Tvix” talk at NixCon&lt;/a&gt; to learn more about our progress and plans.&lt;/li&gt;
&lt;li&gt;If you’d like to help out by hacking on Rust and Tvix, join us at &lt;a href=&quot;https://oceansprint.org/&quot;&gt;OceanSprint&lt;/a&gt; for a week of hacking.&lt;/li&gt;
&lt;li&gt;Join the &lt;a href=&quot;https://discord.gg/naMgvexb6q&quot;&gt;devenv Discord community&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Join &lt;a href=&quot;https://matrix.to/#/#tvix-dev:hackint.org&quot;&gt;#tvix-dev on Matrix&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Subscribe to the mailing list for future announcements at the bottom of the page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>devenv 1.3: Instant developer environments with Nix caching</title><link>https://devenv.sh/blog/2024/10/03/devenv-13-instant-developer-environments-with-nix-caching/</link><guid isPermaLink="true">https://devenv.sh/blog/2024/10/03/devenv-13-instant-developer-environments-with-nix-caching/</guid><pubDate>Thu, 03 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hot on the heels of the &lt;a href=&quot;https://devenv.sh/blog/2024/09/24/devenv-12-tasks-for-convergent-configuration-with-nix/&quot;&gt;previous release of tasks&lt;/a&gt;,
we’re releasing devenv 1.3! 🎉&lt;/p&gt;
&lt;p&gt;This release brings precise caching to Nix evaluation, significantly speeding up developer environments.&lt;/p&gt;
&lt;p&gt;Once cached, the results of a Nix eval or build can be recalled in single-digit milliseconds.&lt;/p&gt;
&lt;p&gt;If any of the automatically-detected inputs change, the cache is invalidated and the build is performed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://devenv.sh/assets/images/caching.gif&quot; alt=&quot;Caching comparison&quot;&gt;&lt;/p&gt;
&lt;aside aria-label=&quot;Note&quot;&gt;&lt;p aria-hidden=&quot;true&quot;&gt;Note&lt;/p&gt;&lt;div&gt;&lt;p&gt;If you run into any issues, run devenv with &lt;code dir=&quot;auto&quot;&gt;--refresh-eval-cache&lt;/code&gt; and report
&lt;a href=&quot;https://github.com/cachix/devenv/issues/new?assignees=&amp;#x26;labels=bug&amp;#x26;projects=&amp;#x26;template=bug_report.md&amp;#x26;title=&quot;&gt;an issue&lt;/a&gt;.&lt;/p&gt;&lt;/div&gt;&lt;/aside&gt;
&lt;div&gt;&lt;h2 id=&quot;how-does-it-work&quot;&gt;How does it work?&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Behind the scenes, devenv now parses Nix’s internal logs to determine which files and directories were accessed during evaluation.&lt;/p&gt;
&lt;p&gt;This approach is very much inspired by &lt;a href=&quot;https://github.com/nix-community/lorri&quot;&gt;lorri&lt;/a&gt;, but doesn’t require a daemon running in the background.&lt;/p&gt;
&lt;p&gt;The caching process works as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;During Nix evaluation, devenv parses the Nix logs for any files and directories that are accessed.&lt;/li&gt;
&lt;li&gt;For each accessed path, we store:
&lt;ul&gt;
&lt;li&gt;the full path&lt;/li&gt;
&lt;li&gt;a hash of the file contents&lt;/li&gt;
&lt;li&gt;the last modification timestamp&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This metadata is then saved to a SQLite database for quick retrieval.&lt;/p&gt;
&lt;p&gt;When you run a devenv command, we:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Check the database for all previously accessed paths&lt;/li&gt;
&lt;li&gt;Compare the current file hashes and timestamps to the stored values&lt;/li&gt;
&lt;li&gt;If any differences are detected, we invalidate the cache and perform a full re-evaluation&lt;/li&gt;
&lt;li&gt;If no differences are found, we use the cached results, significantly speeding up the process&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This approach allows us to efficiently detect changes in your project, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Direct modifications to Nix files&lt;/li&gt;
&lt;li&gt;Changes to imported files or directories&lt;/li&gt;
&lt;li&gt;Updates to files read using Nix built-ins, like &lt;code dir=&quot;auto&quot;&gt;readFile&lt;/code&gt; or &lt;code dir=&quot;auto&quot;&gt;readDir&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;h2 id=&quot;comparison-with-nixs-built-in-flake-evaluation-cache&quot;&gt;Comparison with Nix’s built-in flake evaluation cache&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Nix’s built-in flake evaluation caches outputs based on the lock of the inputs,
ignoring changes to Nix evaluation that often happen during development workflow.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;comparison-with-existing-tools&quot;&gt;Comparison with existing tools&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;Let’s take a closer look at how devenv’s new caching system compares to other popular tools in the Nix ecosystem.
Running our own cache gives us more control and visibility over the caching process, and allows us to improve our integration with other tools, like direnv.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;lorri&quot;&gt;lorri&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;While lorri pioneered the approach of parsing Nix’s internal logs for caching,
devenv builds on this concept, integrating caching as a built-in feature that works automatically without additional setup.&lt;/p&gt;
&lt;div&gt;&lt;h3 id=&quot;direnv-and-nix-direnv&quot;&gt;direnv and nix-direnv&lt;/h3&gt;&lt;/div&gt;
&lt;p&gt;These tools excel at caching evaluated Nix environments, but have limitations in change detection:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Manual file watching: Users often need to manually specify which files to watch for changes.&lt;/li&gt;
&lt;li&gt;Limited scope: They typically can’t detect changes in deeply nested imports or files read by Nix built-ins.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To leverage devenv’s caching capabilities with direnv, we’ve updated the &lt;code dir=&quot;auto&quot;&gt;.envrc&lt;/code&gt; file to utilize devenv’s new caching logic.&lt;/p&gt;
&lt;p&gt;If you currently enjoy the convenience of our direnv integration to reload your development environment, make sure to update your &lt;code dir=&quot;auto&quot;&gt;.envrc&lt;/code&gt; to:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;source_url &quot;https://raw.githubusercontent.com/cachix/devenv/82c0147677e510b247d8b9165c54f73d32dfd899/direnvrc&quot; &quot;sha256-7u4iDd1nZpxL4tCzmPG0dQgC5V+/44Ba+tHkPob1v2k=&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;use devenv&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;to benefit from the new caching system.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;whats-next&quot;&gt;What’s next?&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;nix develop&lt;/code&gt; currently remains the last bit that’s rather slow and uncacheable, particularly on macOS.
We’re working on bringing its functionality in-house to further bring down the overhead of launching a cached shell to under 100ms.&lt;/p&gt;
&lt;p&gt;Join us on &lt;a href=&quot;https://discord.gg/naMgvexb6q&quot;&gt;Discord&lt;/a&gt; if you have any questions,&lt;/p&gt;
&lt;p&gt;Domen &amp;#x26; Sander&lt;/p&gt;
</content:encoded></item><item><title>devenv 1.2: Tasks for convergent configuration with Nix</title><link>https://devenv.sh/blog/2024/09/24/devenv-12-tasks-for-convergent-configuration-with-nix/</link><guid isPermaLink="true">https://devenv.sh/blog/2024/09/24/devenv-12-tasks-for-convergent-configuration-with-nix/</guid><pubDate>Tue, 24 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;For devenv, our mission is to make Nix the ultimate tool for managing developer environments. Nix
excels at &lt;a href=&quot;https://constructolution.wordpress.com/2012/07/08/divergent-convergent-and-congruent-infrastructures/&quot;&gt;congruent configuration&lt;/a&gt;,
where the system state is fully described by declarative code.&lt;/p&gt;
&lt;p&gt;However, the real world often throws curveballs. Side-effects like database migrations, one-off
tasks such as data imports, or external API calls don’t always fit neatly into this paradigm.
In these cases, we often resort to &lt;a href=&quot;https://constructolution.wordpress.com/2012/07/08/divergent-convergent-and-congruent-infrastructures/&quot;&gt;convergent configuration&lt;/a&gt;,
where we define the desired end-state and let the system figure out how to get there.&lt;/p&gt;
&lt;p&gt;To bridge this gap and make Nix more versatile, we’re introducing tasks. These allow you to
handle those pesky real-world scenarios while still leveraging Nix’s powerful ecosystem.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://devenv.sh/assets/images/tasks.gif&quot; alt=&quot;Tasks interactive example&quot;&gt;&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;For example if you’d like to execute python code after virtualenv has been created:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;python&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;languages&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;python&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;venv&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;enable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;tasks&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;python:setup&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;exec&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;python &lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;writeText&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;setup.py&quot;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;          &lt;/span&gt;&lt;/span&gt;&lt;span&gt;print(&quot;hello world&quot;)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&apos;&apos;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;      &lt;/span&gt;&lt;span&gt;after&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;devenv:python:virtualenv&quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;&quot;devenv:enterShell&quot;&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;after&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;python:setup&quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;&lt;code dir=&quot;auto&quot;&gt;python:setup&lt;/code&gt; task executes before &lt;code dir=&quot;auto&quot;&gt;devenv:enterShell&lt;/code&gt; but after &lt;code dir=&quot;auto&quot;&gt;python:virtualenv&lt;/code&gt; task:&lt;/p&gt;
&lt;p&gt;For all supported use cases see &lt;a href=&quot;https://devenv.sh/tasks/&quot;&gt;tasks documentation&lt;/a&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;task-server-protocol-for-sdks&quot;&gt;Task Server Protocol for SDKs&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;We’ve talked to many teams that &lt;strong&gt;dropped Nix&lt;/strong&gt; after a while and they usually fit into two categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;Maintaining &lt;strong&gt;Nix was too complex&lt;/strong&gt; and the team didn’t fully onboard, &lt;strong&gt;creating friction inside the teams&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Went &lt;strong&gt;all-in Nix&lt;/strong&gt; and it took &lt;strong&gt;a big toll on the team productivity&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While devenv already addresses (1), bridging &lt;strong&gt;the gap between Nix provided developer environments
and existing devops tooling written in your favorite language is still an unsolved problem until now&lt;/strong&gt;.
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;We’ve designed &lt;a href=&quot;https://github.com/cachix/devenv/issues/1457&quot;&gt;Task Server Protocol&lt;/a&gt; so that you can write tasks
using your existing automation by providing an executable that exposes the tasks to devenv:
&lt;br&gt;&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}:&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;let&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;myexecutable&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;rustPlatform&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;buildRustPackage&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;rec&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;pname&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;foo-bar&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;version&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;0.1&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;cargoLock&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;lockFile&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;./myexecutable/Cargo.lock&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;src&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;cleanSource&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;./myexecutable&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;in {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;task&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;serverProtocol&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; [ &lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;${&lt;/span&gt;&lt;span&gt;myexecutable&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;/bin/myexecutable&quot;&lt;/span&gt;&lt;span&gt; ];&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;In a few weeks we’re planning to provide &lt;a href=&quot;https://github.com/cachix/devenv/issues/1457&quot;&gt;Rust TSP SDK&lt;/a&gt;
with a &lt;strong&gt;full test suite&lt;/strong&gt; so you can implement your own abstraction in your language of choice.
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;You can now use your &lt;strong&gt;preferred language for automation&lt;/strong&gt;, running tasks with a simple &lt;code dir=&quot;auto&quot;&gt;devenv tasks run &amp;#x3C;names&gt;&lt;/code&gt; command. This
&lt;strong&gt;flexibility&lt;/strong&gt; allows for more &lt;strong&gt;intuitive and maintainable scripts&lt;/strong&gt;, tailored to your team’s familiarity.&lt;/p&gt;
&lt;p&gt;For devenv itself, we’ll slowly &lt;strong&gt;transition from bash to Rust for
internal glue code&lt;/strong&gt;, enhancing performance and reliability. This change will make devenv more
&lt;strong&gt;robust and easier to extend&lt;/strong&gt;, ultimately providing you with a &lt;strong&gt;smoother development experience&lt;/strong&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;upgrading&quot;&gt;Upgrading&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;If you run &lt;code dir=&quot;auto&quot;&gt;devenv update&lt;/code&gt; on your existing repository you should already be using tasks,
without needing to upgrade to devenv 1.2.&lt;/p&gt;
&lt;p&gt;Domen&lt;/p&gt;
</content:encoded></item><item><title>devenv 1.1: Nested Nix outputs using the module system</title><link>https://devenv.sh/blog/2024/09/11/devenv-11-nested-nix-outputs-using-the-module-system/</link><guid isPermaLink="true">https://devenv.sh/blog/2024/09/11/devenv-11-nested-nix-outputs-using-the-module-system/</guid><pubDate>Wed, 11 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/releases/tag/v1.1&quot;&gt;devenv 1.1&lt;/a&gt; brings support for Nix outputs, matching the last missing piece of functionality with Flakes.
&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;It was designed to make outputs extensible, nested, and &lt;a href=&quot;https://github.com/NixOS/nix/issues/7165&quot;&gt;buildable as a whole by default&lt;/a&gt;.
&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;This allows exposing Nix packages for installation/consumption by other tools.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;nested-nix-outputs&quot;&gt;Nested Nix outputs&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;If you have a devenv with outputs like this:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;outputs&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;myproject&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;myapp&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;./myapp&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;inherit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;; };&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;You can build all outputs by running:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/nix/store/mzq5bpi49h26cy2mfj5a2r0q69fh3a9k-git-2.44.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/nix/store/mzq5bpi49h26cy2mfj5a2r0q71fh3a9k-myapp-1.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Or build specific attribute(s) by listing them explicitly:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;outputs.git&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/nix/store/mzq5bpi49h26cy2mfj5a2r0q69fh3a9k-git-2.44.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;This is useful for tools that need to find and install specific outputs.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;defining-outputs-as-module-options&quot;&gt;Defining outputs as module options&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;By default, any derivation specified in &lt;code dir=&quot;auto&quot;&gt;outputs&lt;/code&gt; nested attributes set is recognized as an output.
&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;You can define custom options as output types in &lt;code dir=&quot;auto&quot;&gt;devenv&lt;/code&gt;. These will be automatically detected and built:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;devenv.nix&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;{ &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;... &lt;/span&gt;&lt;span&gt;}: {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;options&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;myapp&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;package&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;mkOption&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;types&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;outputOf&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;lib&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;types&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;package&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;description&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;The package for myapp&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;default&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;./myapp&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;inherit&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;; };&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;        &lt;/span&gt;&lt;span&gt;defaultText&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;myapp-1.0&quot;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;    &lt;/span&gt;&lt;span&gt;outputs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;pkgs&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;Building will pick up all outputs, in this case &lt;code dir=&quot;auto&quot;&gt;myapp.package&lt;/code&gt; and &lt;code dir=&quot;auto&quot;&gt;outputs.git&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;$&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devenv&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/nix/store/mzq5bpi49h26cy2mfj5a2r0q69fh3a9k-myapp-1.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span&gt;/nix/store/mzq5bpi49h26cy2mfj5a2r0q69fh3a9k-git-2.44.0&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/div&gt;
&lt;p&gt;If you don’t want to specify the output type, you can just use &lt;code dir=&quot;auto&quot;&gt;config.lib.types.output&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;referencing-outputs-from-another-devenv&quot;&gt;Referencing outputs from another devenv&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;If you &lt;a href=&quot;https://devenv.sh/composing-using-imports/&quot;&gt;import another &lt;code dir=&quot;auto&quot;&gt;devenv.nix&lt;/code&gt; file&lt;/a&gt;, the outputs will be merged together,
allowing you to compose a developer environment and outputs in one logical unit.
&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;You could also import outputs from other applications as inputs instead of composing them.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cachix/devenv/issues/1438&quot;&gt;Leave a thumbs on the issue&lt;/a&gt; if you’d like to see it happen.&lt;/p&gt;
&lt;div&gt;&lt;h2 id=&quot;documentation&quot;&gt;Documentation&lt;/h2&gt;&lt;/div&gt;
&lt;p&gt;See &lt;a href=&quot;https://devenv.sh/outputs/&quot;&gt;Outputs&lt;/a&gt; section in documentation for the latest comprehensive guide to outputs.
&lt;br&gt;&lt;br&gt;&lt;/p&gt;
&lt;p&gt;We’re on &lt;a href=&quot;https://discord.gg/naMgvexb6q&quot;&gt;Discord&lt;/a&gt; if you need help, Domen&lt;/p&gt;
</content:encoded></item></channel></rss>