diff --git a/.circleci/config.yml b/.circleci/config.yml
index 45eaa02f4beed2da63fc2ba7347892fdd5541ccc..1be9adc7afcd45f5c139e1beca4e1596a2a13f68 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -24,8 +24,7 @@ jobs:
       - run:
           name: "Run Tests"
           command: |
-            export NIX_PATH=nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/$(cat nixpkgs.rev).tar.gz
-            nix-build nixos/unit-tests.nix && cat result
+            nix-shell --run 'nix-build nixos/unit-tests.nix' && cat result
 
   system-tests-driver:
     # Cannot actually run the system tests on CircleCI but we can build
@@ -54,14 +53,13 @@ jobs:
             # If nixpkgs changes then potentially a lot of cached packages for
             # the base system will be invalidated so we may as well drop them
             # and make a new cache with the new packages.
-            - privatestorageio-nix-store-v2-{{ checksum "nixpkgs.rev" }}
+            - privatestorageio-nix-store-v2-{{ checksum "nixpkgs.json" }}
             - privatestorageio-nix-store-v2-
 
       - run:
           name: "Build System Test Driver"
           command: |
-            export NIX_PATH=nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/$(cat nixpkgs.rev).tar.gz
-            nix-build --max-jobs 1 --cores 1 nixos/system-tests.nix -A driver
+            nix-shell --run 'nix-build --max-jobs 1 --cores 1 nixos/system-tests.nix -A driver'
 
           # Give it a good long while.  PaymentServer and its dependencies, in
           # particular, can take a while to build.
@@ -69,7 +67,7 @@ jobs:
 
       - save_cache:
           name: "Cache Nix Store Paths"
-          key: privatestorageio-nix-store-v2-{{ checksum "nixpkgs.rev" }}
+          key: privatestorageio-nix-store-v2-{{ checksum "nixpkgs.json" }}
           paths:
             - "/nix"
 
@@ -83,18 +81,17 @@ jobs:
           # See comments for nix store caching in `build` job.
           name: "Restore Nix Store Paths"
           keys:
-            - privatestorageio-docs-nix-store-v1-{{ checksum "nixpkgs.rev" }}
+            - privatestorageio-docs-nix-store-v1-{{ checksum "nixpkgs.json" }}
             - privatestorageio-docs-nix-store-v1-
 
       - run:
           name: "Nix Build"
           command: |
-            export NIX_PATH=nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/$(cat nixpkgs.rev).tar.gz
-            nix-build docs.nix
+            nix-shell --run 'nix-build docs.nix'
 
       - save_cache:
           name: "Cache Nix Store Paths"
-          key: privatestorageio-docs-nix-store-v1-{{ checksum "nixpkgs.rev" }}
+          key: privatestorageio-docs-nix-store-v1-{{ checksum "nixpkgs.json" }}
           paths:
             - "/nix"
 
diff --git a/README.rst b/README.rst
index 7bd9f0fcabc91d6d95351893d5e0da3da653ca77..9a847edbb7975ceb4775dc15a5af125a83c687af 100644
--- a/README.rst
+++ b/README.rst
@@ -7,10 +7,9 @@ Building
 --------
 
 The build system uses `Nix`_ which must be installed before anything can be built.
-Builds are tested against a particular nixpkgs revision.
-Start by exporting ``NIX_PATH`` to ensure you use the same revision::
+Start by setting up the development/operations environment::
 
-  $ export NIX_PATH=nixpkgs=https://github.com/NixOS/nixpkgs-channels/archive/$(cat nixpkgs.rev).tar.gz
+  $ nix-shell
 
 Documentation
 ~~~~~~~~~~~~~
diff --git a/nixpkgs.json b/nixpkgs.json
new file mode 100644
index 0000000000000000000000000000000000000000..25e71e44cd7635329b2dd2e0b43d662165c51328
--- /dev/null
+++ b/nixpkgs.json
@@ -0,0 +1,3 @@
+{ "url": "https://github.com/NixOS/nixpkgs-channels/archive/353333ef340952c05332e3c271dff953264cb017.tar.gz"
+, "sha256": "sha256:0bv34yz892yxhx2kb8a1yr5pm0g8ck5w021yj87r7kfnp416apdh"
+}
diff --git a/nixpkgs.rev b/nixpkgs.rev
deleted file mode 100644
index 339195d572f2a1784ed2ed911834e0e571d639e2..0000000000000000000000000000000000000000
--- a/nixpkgs.rev
+++ /dev/null
@@ -1 +0,0 @@
-353333ef340952c05332e3c271dff953264cb017
\ No newline at end of file
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 0000000000000000000000000000000000000000..26aaad6035ca9b16f36eb832d591bddce8a93cbb
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,22 @@
+let
+  nixpkgs-pin = builtins.fromJSON (builtins.readFile ./nixpkgs.json);
+  nixpkgs-src = builtins.fetchTarball nixpkgs-pin;
+  nixpkgs = import nixpkgs-src { };
+in
+{ pkgs ? nixpkgs }:
+let
+  # Get a version of Morph known to work with our version of NixOS.
+  morph-src = pkgs.fetchFromGitHub {
+    owner = "DBCDK";
+    repo = "morph";
+    rev = "3856a9c2f733192dee1600b8655715d760ba1803";
+    hash = "sha256:0jhypvj45yjg4cn4rvb2j9091pl6z5j541vcfaln5sb3ds14fkwf";
+  };
+  morph = pkgs.callPackage (morph-src + "/nix-packaging") { };
+in
+pkgs.mkShell {
+  NIX_PATH = "nixpkgs=${nixpkgs-pin.url}";
+  buildInputs = [
+    morph
+  ];
+}