nix: Use flake-parts, partitions, and treefmt-nix (#45321)

Diego Perez and Jakub Konka created

Release Notes:

Refactored:
- Use [flake-parts](https://flake.parts/index.html) modules
- `nix/shell.nix` -> `nix/modules/devshells.nix`

Added:
- Use
[flake-parts.partitions](https://flake.parts/options/flake-parts-partitions.html)
to isolate dev dependencies so that flakes that use `zed-editor` don't
fetch dev-only inputs such as `treefmt-nix`
- [treefmt-nix](https://github.com/numtide/treefmt-nix)
  - nixfmt
  - rustfmt

Fixed:
- `shell.nix` and `default.nix` fetching `flake-compat` from
`flake.lock` which added an extra and unnecessary input/dependency to
`flake.nix`. Fixed by setting a fixed rev and sha256 instead.
- `nixfmt-rfc-style` is deprecated and is now `nixfmt`
- Fixes #45338 by using rust-overlay toolchain directly
  - Previously, the devShell included `rustup` which caused slow startup
times as Nix would build rustup from source (including running its test
suite). Additionally, rust tooling (cargo, rustfmt, clippy,
rust-analyzer) wasn't available in the dev shell.
- cargo, rustc, and rust-toolchain.toml components included in
`rustToolchain`

Chore:
- Update `flake.lock`
- Format Rust code with `rustfmt` via `treefmt-nix`

---------

Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>

Change summary

crates/codestral/src/codestral.rs                            |  2 
crates/collab/src/completion.rs                              |  2 
crates/gpui/src/platform/mac/status_item.rs                  |  9 
crates/ui/src/components/ai/copilot_configuration_callout.rs |  1 
default.nix                                                  |  9 
flake.lock                                                   | 65 +++--
flake.nix                                                    | 45 ---
nix/dev/flake.lock                                           | 45 ++++
nix/dev/flake.nix                                            | 10 
nix/modules/devshells.nix                                    | 60 +++++
nix/modules/overlays.nix                                     | 11 +
nix/modules/packages.nix                                     | 15 +
nix/modules/partitions.nix                                   | 25 ++
nix/modules/treefmt.nix                                      | 10 
nix/shell.nix                                                | 63 -----
nix/toolchain.nix                                            |  9 
rust-toolchain.toml                                          |  2 
rustfmt.toml                                                 |  3 
shell.nix                                                    |  9 
19 files changed, 257 insertions(+), 138 deletions(-)

Detailed changes

crates/codestral/src/codestral.rs 🔗

@@ -6,7 +6,7 @@ use gpui::{App, Context, Entity, Task};
 use http_client::HttpClient;
 use icons::IconName;
 use language::{
-    language_settings::all_language_settings, Anchor, Buffer, BufferSnapshot, EditPreview, ToPoint,
+    Anchor, Buffer, BufferSnapshot, EditPreview, ToPoint, language_settings::all_language_settings,
 };
 use language_models::MistralLanguageModelProvider;
 use mistral::CODESTRAL_API_URL;

crates/gpui/src/platform/mac/status_item.rs 🔗

@@ -1,18 +1,17 @@
 use crate::{
+    Scene,
     geometry::{
         rect::RectF,
-        vector::{vec2f, Vector2F},
+        vector::{Vector2F, vec2f},
     },
     platform::{
-        self,
+        self, Event, FontSystem, WindowBounds,
         mac::{platform::NSViewLayerContentsRedrawDuringViewResize, renderer::Renderer},
-        Event, FontSystem, WindowBounds,
     },
-    Scene,
 };
 use cocoa::{
     appkit::{NSScreen, NSSquareStatusItemLength, NSStatusBar, NSStatusItem, NSView, NSWindow},
-    base::{id, nil, YES},
+    base::{YES, id, nil},
     foundation::{NSPoint, NSRect, NSSize},
 };
 use ctor::ctor;

default.nix 🔗

@@ -1,11 +1,10 @@
 (import (
   let
-    lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+    rev = "v1.1.0";
+    sha256 = "sha256:19d2z6xsvpxm184m41qrpi1bplilwipgnzv9jy17fgw421785q1m";
   in
   fetchTarball {
-    url =
-      lock.nodes.flake-compat.locked.url
-        or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
-    sha256 = lock.nodes.flake-compat.locked.narHash;
+    inherit sha256;
+    url = "https://github.com/NixOS/flake-compat/archive/${rev}.tar.gz";
   }
 ) { src = ./.; }).defaultNix

flake.lock 🔗

@@ -2,11 +2,11 @@
   "nodes": {
     "crane": {
       "locked": {
-        "lastModified": 1768873933,
-        "narHash": "sha256-CfyzdaeLNGkyAHp3kT5vjvXhA1pVVK7nyDziYxCPsNk=",
+        "lastModified": 1769737823,
+        "narHash": "sha256-DrBaNpZ+sJ4stXm+0nBX7zqZT9t9P22zbk6m5YhQxS4=",
         "owner": "ipetkov",
         "repo": "crane",
-        "rev": "0bda7e7d005ccb5522a76d11ccfbf562b71953ca",
+        "rev": "b2f45c3830aa96b7456a4c4bc327d04d7a43e1ba",
         "type": "github"
       },
       "original": {
@@ -15,38 +15,59 @@
         "type": "github"
       }
     },
-    "flake-compat": {
+    "flake-parts": {
+      "inputs": {
+        "nixpkgs-lib": "nixpkgs-lib"
+      },
       "locked": {
-        "lastModified": 1767039857,
-        "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
-        "owner": "edolstra",
-        "repo": "flake-compat",
-        "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
+        "lastModified": 1769996383,
+        "narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
+        "rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
         "type": "github"
       },
       "original": {
-        "owner": "edolstra",
-        "repo": "flake-compat",
+        "owner": "hercules-ci",
+        "repo": "flake-parts",
         "type": "github"
       }
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1768875095,
-        "narHash": "sha256-XH6awru9NnBc/m+2YhRNT8r1PAKEiPGF3gs//F3ods0=",
-        "rev": "ed142ab1b3a092c4d149245d0c4126a5d7ea00b0",
-        "type": "tarball",
-        "url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre930822.ed142ab1b3a0/nixexprs.tar.xz"
+        "lastModified": 1769789167,
+        "narHash": "sha256-kKB3bqYJU5nzYeIROI82Ef9VtTbu4uA3YydSk/Bioa8=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "62c8382960464ceb98ea593cb8321a2cf8f9e3e5",
+        "type": "github"
       },
       "original": {
-        "type": "tarball",
-        "url": "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "nixpkgs-lib": {
+      "locked": {
+        "lastModified": 1769909678,
+        "narHash": "sha256-cBEymOf4/o3FD5AZnzC3J9hLbiZ+QDT/KDuyHXVJOpM=",
+        "owner": "nix-community",
+        "repo": "nixpkgs.lib",
+        "rev": "72716169fe93074c333e8d0173151350670b824c",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "nixpkgs.lib",
+        "type": "github"
       }
     },
     "root": {
       "inputs": {
         "crane": "crane",
-        "flake-compat": "flake-compat",
+        "flake-parts": "flake-parts",
         "nixpkgs": "nixpkgs",
         "rust-overlay": "rust-overlay"
       }
@@ -58,11 +79,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1769136478,
-        "narHash": "sha256-8UNd5lmGf8phCr/aKxagJ4kNsF0pCHLish2G4ZKCFFY=",
+        "lastModified": 1770001842,
+        "narHash": "sha256-ZAyTeILfdWwDp1nuF0RK3McBduMi49qnJvrS+3Ezpac=",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "470ee44393bb19887056b557ea2c03fc5230bd5a",
+        "rev": "5018343419ea808f8a413241381976b7e60951f2",
         "type": "github"
       },
       "original": {

flake.nix 🔗

@@ -2,23 +2,18 @@
   description = "High-performance, multiplayer code editor from the creators of Atom and Tree-sitter";
 
   inputs = {
-    nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz";
+    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+    flake-parts.url = "github:hercules-ci/flake-parts";
+    crane.url = "github:ipetkov/crane";
     rust-overlay = {
       url = "github:oxalica/rust-overlay";
       inputs.nixpkgs.follows = "nixpkgs";
     };
-    crane.url = "github:ipetkov/crane";
-    flake-compat.url = "github:edolstra/flake-compat";
   };
 
   outputs =
-    {
-      nixpkgs,
-      rust-overlay,
-      crane,
-      ...
-    }:
-    let
+    inputs@{ flake-parts, ... }:
+    flake-parts.lib.mkFlake { inherit inputs; } {
       systems = [
         "x86_64-linux"
         "x86_64-darwin"
@@ -26,31 +21,11 @@
         "aarch64-darwin"
       ];
 
-      forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f nixpkgs.legacyPackages.${system});
-      mkZed =
-        pkgs:
-        let
-          rustBin = rust-overlay.lib.mkRustBin { } pkgs;
-        in
-        pkgs.callPackage ./nix/build.nix {
-          crane = crane.mkLib pkgs;
-          rustToolchain = rustBin.fromRustupToolchainFile ./rust-toolchain.toml;
-        };
-    in
-    {
-      packages = forAllSystems (pkgs: rec {
-        default = mkZed pkgs;
-        debug = default.override { profile = "dev"; };
-      });
-      devShells = forAllSystems (pkgs: {
-        default = pkgs.callPackage ./nix/shell.nix {
-          zed-editor = mkZed pkgs;
-        };
-      });
-      formatter = forAllSystems (pkgs: pkgs.nixfmt-rfc-style);
-      overlays.default = final: _: {
-        zed-editor = mkZed final;
-      };
+      imports = [
+        ./nix/modules/overlays.nix
+        ./nix/modules/packages.nix
+        ./nix/modules/partitions.nix
+      ];
     };
 
   nixConfig = {

nix/dev/flake.lock 🔗

@@ -0,0 +1,45 @@
+{
+  "nodes": {
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1761236834,
+        "narHash": "sha256-+pthv6hrL5VLW2UqPdISGuLiUZ6SnAXdd2DdUE+fV2Q=",
+        "owner": "nixos",
+        "repo": "nixpkgs",
+        "rev": "d5faa84122bc0a1fd5d378492efce4e289f8eac1",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nixos",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "treefmt-nix": "treefmt-nix"
+      }
+    },
+    "treefmt-nix": {
+      "inputs": {
+        "nixpkgs": "nixpkgs"
+      },
+      "locked": {
+        "lastModified": 1766000401,
+        "narHash": "sha256-+cqN4PJz9y0JQXfAK5J1drd0U05D5fcAGhzhfVrDlsI=",
+        "owner": "numtide",
+        "repo": "treefmt-nix",
+        "rev": "42d96e75aa56a3f70cab7e7dc4a32868db28e8fd",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "treefmt-nix",
+        "type": "github"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}

nix/dev/flake.nix 🔗

@@ -0,0 +1,10 @@
+{
+  description = "Private inputs for development purposes. These are used by the top level flake in the `dev` partition, but do not appear in consumers' lock files.";
+
+  inputs = {
+    treefmt-nix.url = "github:numtide/treefmt-nix";
+  };
+
+  # This flake is only used for its inputs.
+  outputs = { ... }: { };
+}

nix/modules/devshells.nix 🔗

@@ -0,0 +1,60 @@
+{ inputs, ... }:
+{
+  perSystem =
+    { pkgs, ... }:
+    let
+      # NOTE: Duplicated because this is in a separate flake-parts partition
+      # than ./packages.nix
+      mkZed = import ../toolchain.nix { inherit inputs; };
+      zed-editor = mkZed pkgs;
+
+      rustBin = inputs.rust-overlay.lib.mkRustBin { } pkgs;
+      rustToolchain = rustBin.fromRustupToolchainFile ../../rust-toolchain.toml;
+
+      baseEnv =
+        (zed-editor.overrideAttrs (attrs: {
+          passthru.env = attrs.env;
+        })).env; # exfil `env`; it's not in drvAttrs
+    in
+    {
+      devShells.default = (pkgs.mkShell.override { inherit (zed-editor) stdenv; }) {
+        name = "zed-editor-dev";
+        inputsFrom = [ zed-editor ];
+
+        packages = with pkgs; [
+          rustToolchain # cargo, rustc, and rust-toolchain.toml components included
+          cargo-nextest
+          cargo-hakari
+          cargo-machete
+          cargo-zigbuild
+          # TODO: package protobuf-language-server for editing zed.proto
+          # TODO: add other tools used in our scripts
+
+          # `build.nix` adds this to the `zed-editor` wrapper (see `postFixup`)
+          # we'll just put it on `$PATH`:
+          nodejs_22
+          zig
+        ];
+
+        env =
+          (removeAttrs baseEnv [
+            "LK_CUSTOM_WEBRTC" # download the staticlib during the build as usual
+            "ZED_UPDATE_EXPLANATION" # allow auto-updates
+            "CARGO_PROFILE" # let you specify the profile
+            "TARGET_DIR"
+          ])
+          // {
+            # note: different than `$FONTCONFIG_FILE` in `build.nix` – this refers to relative paths
+            # outside the nix store instead of to `$src`
+            FONTCONFIG_FILE = pkgs.makeFontsConf {
+              fontDirectories = [
+                "./assets/fonts/lilex"
+                "./assets/fonts/ibm-plex-sans"
+              ];
+            };
+            PROTOC = "${pkgs.protobuf}/bin/protoc";
+            ZED_ZSTD_MUSL_LIB = "${pkgs.pkgsCross.musl64.pkgsStatic.zstd.out}/lib";
+          };
+      };
+    };
+}

nix/modules/overlays.nix 🔗

@@ -0,0 +1,11 @@
+{ inputs, ... }:
+{
+  flake.overlays.default =
+    final: _:
+    let
+      mkZed = import ../toolchain.nix { inherit inputs; };
+    in
+    {
+      zed-editor = mkZed final;
+    };
+}

nix/modules/packages.nix 🔗

@@ -0,0 +1,15 @@
+{ inputs, ... }:
+{
+  perSystem =
+    { pkgs, ... }:
+    let
+      mkZed = import ../toolchain.nix { inherit inputs; };
+      zed-editor = mkZed pkgs;
+    in
+    {
+      packages = {
+        default = zed-editor;
+        debug = zed-editor.override { profile = "dev"; };
+      };
+    };
+}

nix/modules/partitions.nix 🔗

@@ -0,0 +1,25 @@
+{ inputs, ... }:
+{
+  imports = [
+    inputs.flake-parts.flakeModules.partitions
+  ];
+
+  partitionedAttrs = {
+    devShells = "dev";
+    formatter = "dev";
+    checks = "dev";
+  };
+
+  partitions.dev = {
+    extraInputsFlake = ../dev;
+    module =
+      { inputs, ... }:
+      {
+        imports = [
+          inputs.treefmt-nix.flakeModule
+          ./devshells.nix
+          ./treefmt.nix
+        ];
+      };
+  };
+}

nix/modules/treefmt.nix 🔗

@@ -0,0 +1,10 @@
+{
+  perSystem =
+    { pkgs, ... }:
+    {
+      treefmt = {
+        programs.nixfmt.enable = true;
+        programs.rustfmt.enable = true;
+      };
+    };
+}

nix/shell.nix 🔗

@@ -1,63 +0,0 @@
-{
-  mkShell,
-  makeFontsConf,
-  pkgsCross,
-
-  zed-editor,
-
-  rust-analyzer,
-  rustup,
-  cargo-nextest,
-  cargo-hakari,
-  cargo-machete,
-  cargo-zigbuild,
-  nixfmt-rfc-style,
-  protobuf,
-  nodejs_22,
-  zig,
-}:
-(mkShell.override { inherit (zed-editor) stdenv; }) {
-  inputsFrom = [ zed-editor ];
-  packages = [
-    rust-analyzer
-    rustup
-    cargo-nextest
-    cargo-hakari
-    cargo-machete
-    cargo-zigbuild
-    nixfmt-rfc-style
-    # TODO: package protobuf-language-server for editing zed.proto
-    # TODO: add other tools used in our scripts
-
-    # `build.nix` adds this to the `zed-editor` wrapper (see `postFixup`)
-    # we'll just put it on `$PATH`:
-    nodejs_22
-    zig
-  ];
-
-  env =
-    let
-      baseEnvs =
-        (zed-editor.overrideAttrs (attrs: {
-          passthru = { inherit (attrs) env; };
-        })).env; # exfil `env`; it's not in drvAttrs
-    in
-    (removeAttrs baseEnvs [
-      "LK_CUSTOM_WEBRTC" # download the staticlib during the build as usual
-      "ZED_UPDATE_EXPLANATION" # allow auto-updates
-      "CARGO_PROFILE" # let you specify the profile
-      "TARGET_DIR"
-    ])
-    // {
-      # note: different than `$FONTCONFIG_FILE` in `build.nix` – this refers to relative paths
-      # outside the nix store instead of to `$src`
-      FONTCONFIG_FILE = makeFontsConf {
-        fontDirectories = [
-          "./assets/fonts/lilex"
-          "./assets/fonts/ibm-plex-sans"
-        ];
-      };
-      PROTOC = "${protobuf}/bin/protoc";
-      ZED_ZSTD_MUSL_LIB = "${pkgsCross.musl64.pkgsStatic.zstd.out}/lib";
-    };
-}

nix/toolchain.nix 🔗

@@ -0,0 +1,9 @@
+{ inputs, ... }:
+pkgs:
+let
+  rustBin = inputs.rust-overlay.lib.mkRustBin { } pkgs;
+in
+pkgs.callPackage ./build.nix {
+  crane = inputs.crane.mkLib pkgs;
+  rustToolchain = rustBin.fromRustupToolchainFile ../rust-toolchain.toml;
+}

rust-toolchain.toml 🔗

@@ -1,7 +1,7 @@
 [toolchain]
 channel = "1.93"
 profile = "minimal"
-components = [ "rustfmt", "clippy" ]
+components = [ "rustfmt", "clippy", "rust-analyzer" ]
 targets = [
     "wasm32-wasip2", # extensions
     "x86_64-unknown-linux-musl", # remote server

rustfmt.toml 🔗

@@ -0,0 +1,3 @@
+# https://github.com/rust-lang/rustfmt?tab=readme-ov-file#rusts-editions 
+edition = "2024"
+style_edition = "2024"

shell.nix 🔗

@@ -1,11 +1,10 @@
 (import (
   let
-    lock = builtins.fromJSON (builtins.readFile ./flake.lock);
+    rev = "v1.1.0";
+    sha256 = "sha256:19d2z6xsvpxm184m41qrpi1bplilwipgnzv9jy17fgw421785q1m";
   in
   fetchTarball {
-    url =
-      lock.nodes.flake-compat.locked.url
-        or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
-    sha256 = lock.nodes.flake-compat.locked.narHash;
+    inherit sha256;
+    url = "https://github.com/NixOS/flake-compat/archive/${rev}.tar.gz";
   }
 ) { src = ./.; }).shellNix