diff --git a/.github/actions/nix-devshell/action.yaml b/.github/actions/nix-devshell/action.yaml
index 1a7590f5..bc6b147f 100644
--- a/.github/actions/nix-devshell/action.yaml
+++ b/.github/actions/nix-devshell/action.yaml
@@ -4,7 +4,28 @@ runs:
   using: "composite"
   steps:
     - name: Setup Nix
-      uses: DeterminateSystems/nix-installer-action@e50d5f73bfe71c2dd0aa4218de8f4afa59f8f81d # v16
+      uses: nixbuild/nix-quick-install-action@5bb6a3b3abe66fd09bbf250dce8ada94f856a703 # v30
+
+    - uses: nix-community/cache-nix-action@92aaf15ec4f2857ffed00023aecb6504bb4a5d3d # v6
+      with:
+        # restore and save a cache using this key
+        primary-key: nix-${{ runner.os }}-${{ hashFiles('**/*.nix', '**/flake.lock') }}
+        # if there's no cache hit, restore a cache by this prefix
+        restore-prefixes-first-match: nix-${{ runner.os }}-
+        # collect garbage until Nix store size (in bytes) is at most this number
+        # before trying to save a new cache
+        # 1 GB = 1073741824 B
+        gc-max-store-size-linux: 1073741824
+        # do purge caches
+        purge: true
+        # purge all versions of the cache
+        purge-prefixes: nix-${{ runner.os }}-
+        # created more than this number of seconds ago relative to the start of the `Post Restore` phase
+        purge-created: 0
+        # except the version with the `primary-key`, if it exists
+        purge-primary-key: never
 
     - name: Enter devshell
       uses: nicknovitski/nix-develop@9be7cfb4b10451d3390a75dc18ad0465bed4932a # v1.2.1
+      with:
+        arguments: ".#ci"
diff --git a/.ignore b/.ignore
new file mode 100644
index 00000000..47ec4742
--- /dev/null
+++ b/.ignore
@@ -0,0 +1 @@
+!.github
diff --git a/Makefile b/Makefile
index ee073008..c03fe39e 100644
--- a/Makefile
+++ b/Makefile
@@ -11,14 +11,18 @@ XCPROJECT := Coder\ Desktop/Coder\ Desktop.xcodeproj
 SCHEME := Coder\ Desktop
 SWIFT_VERSION := 6.0
 
-CURRENT_PROJECT_VERSION:=$(shell git describe --match 'v[0-9]*' --dirty='.devel' --always --tags)
+ifndef CURRENT_PROJECT_VERSION
+	CURRENT_PROJECT_VERSION:=$(shell git describe --match 'v[0-9]*' --dirty='.devel' --always --tags)
+endif
 ifeq ($(strip $(CURRENT_PROJECT_VERSION)),)
-    $(error CURRENT_PROJECT_VERSION cannot be empty)
+	$(error CURRENT_PROJECT_VERSION cannot be empty)
 endif
 
-MARKETING_VERSION:=$(shell git describe --match 'v[0-9]*' --tags --abbrev=0 | sed 's/^v//' | sed 's/-.*$$//')
+ifndef MARKETING_VERSION
+	MARKETING_VERSION:=$(shell git describe --match 'v[0-9]*' --tags --abbrev=0 | sed 's/^v//' | sed 's/-.*$$//')
+endif
 ifeq ($(strip $(MARKETING_VERSION)),)
-    $(error MARKETING_VERSION cannot be empty)
+	$(error MARKETING_VERSION cannot be empty)
 endif
 
 # Define the keychain file name first
diff --git a/flake.lock b/flake.lock
index 5304bdf4..b5b74155 100644
--- a/flake.lock
+++ b/flake.lock
@@ -20,11 +20,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1737885589,
-        "narHash": "sha256-Zf0hSrtzaM1DEz8//+Xs51k/wdSajticVrATqDrfQjg=",
+        "lastModified": 1740560979,
+        "narHash": "sha256-Vr3Qi346M+8CjedtbyUevIGDZW8LcA1fTG0ugPY/Hic=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "852ff1d9e153d8875a83602e03fdef8a63f0ecf8",
+        "rev": "5135c59491985879812717f4c9fea69604e7f26f",
         "type": "github"
       },
       "original": {
diff --git a/flake.nix b/flake.nix
index 5e1e9d8a..f230292a 100644
--- a/flake.nix
+++ b/flake.nix
@@ -53,26 +53,38 @@
         {
           inherit formatter;
 
-          devShells.default = pkgs.mkShellNoCC {
-            buildInputs = with pkgs; [
-              actionlint
-              apple-sdk_15
-              clang
-              coreutils
-              create-dmg
-              formatter
-              gh
-              gnumake
-              protobuf_28
-              protoc-gen-swift
-              swiftformat
-              swiftlint
-              watchexec
-              xcbeautify
-              xcodegen
-              xcpretty
-              zizmor
-            ];
+          devShells = rec {
+            # Need to use a devshell for CI, as we want to reuse the already existing Xcode on the runner
+            ci = pkgs.mkShellNoCC {
+              buildInputs = with pkgs; [
+                actionlint
+                clang
+                coreutils
+                create-dmg
+                gh
+                git
+                gnumake
+                protobuf_28
+                protoc-gen-swift
+                swiftformat
+                swiftlint
+                xcbeautify
+                xcodegen
+                xcpretty
+                zizmor
+              ];
+            };
+
+            default = pkgs.mkShellNoCC {
+              buildInputs =
+                with pkgs;
+                [
+                  apple-sdk_15
+                  formatter
+                  watchexec
+                ]
+                ++ ci.buildInputs;
+            };
           };
         }
       );