diff --git a/morph/grid.nix b/morph/grid.nix
index 8a34f8ee623f6378ed89e94bf557f089568c2412..b6b89c454ba75f8dcfa8d70fcfe8ac9c27e2cfa9 100644
--- a/morph/grid.nix
+++ b/morph/grid.nix
@@ -1,51 +1,28 @@
-let
-  # Pin the deployment package-set to a specific version of nixpkgs.  This is
-  # NixOS 19.03 as of Aug 28 2019.  There's nothing special about it.  It's
-  # just recent at the time of development.  It can be upgraded when there is
-  # value in doing so.  Meanwhile, our platform doesn't shift around beneath
-  # us in surprising ways as time passes.
-  pkgs = import (builtins.fetchTarball {
-    url = "https://github.com/NixOS/nixpkgs/archive/3c83ad6ac13b67101cc3e2e07781963a010c1624.tar.gz";
-    sha256 = "0cdq342wrkvkyccygpp1gvwp7hhqg68hljjwld4vjixm901ayy14";
-  }) {};
-  # Load our JSON configuration for later use.
-  cfg = pkgs.lib.trivial.importJSON ./grid.config.json;
-in
-{
-  network =  {
-    # Make all of the hosts in this network use the nixpkgs we pinned above.
-    inherit pkgs;
-    # This is just for human consumption as far as I can tell.
-    description = "PrivateStorage.io Staging Grid";
-  };
-
-  # Here are the hosts that are in this morph network.  This is sort of like a
-  # server manifest.  We try to keep as many of the specific details as
-  # possible out of *this* file so that this file only grows as server count
-  # grows.  If it grows too much, we can load servers by listing contents of a
-  # directory or reading from another JSON file or some such.  For now, I'm
-  # just manually maintaining these entries.
-  #
-  # The name on the left of the `=` is mostly irrelevant but it does provide a
-  # default hostname for the server if the configuration on the right side
-  # doesn't specify one.
-  #
-  # The names must be unique!
+# Load the helper function and call it with arguments tailored for the testing
+# grid.  It will make the morph configuration for us.  We share this function
+# with the testing grid and have one fewer possible point of divergence.
+import ./make-grid.nix {
+  name = "Production";
+  nodes = cfg: {
+    # Here are the hosts that are in this morph network.  This is sort of like
+    # a server manifest.  We try to keep as many of the specific details as
+    # possible out of *this* file so that this file only grows as server count
+    # grows.  If it grows too much, we can load servers by listing contents of
+    # a directory or reading from another JSON file or some such.  For now,
+    # I'm just manually maintaining these entries.
+    #
+    # The name on the left of the `=` is mostly irrelevant but it does provide
+    # a default hostname for the server if the configuration on the right side
+    # doesn't specify one.
+    #
+    # The names must be unique!
+    "staging001" = import ./staging001.nix {
+      publicIPv4 = "209.95.51.251";
+      inherit (cfg) publicStoragePort;
+    };
 
-  "testing000" = import ./testing000.nix {
-    publicIPv4 = "3.123.26.90";
-    # Pass along some of the Tahoe-LAFS configuration.  If we have much more
-    # configuration than this we may want to keep it bundled up in one value
-    # instead of pulling individual values out to pass along.
-    inherit (cfg) publicStoragePort;
+    # Pass the whole grid configuration to the module and let it take what it
+    # wants.
+    "staging002" = import ./staging002.nix cfg;
   };
-
-  "staging001" = import ./staging001.nix {
-    publicIPv4 = "209.95.51.251";
-    inherit (cfg) publicStoragePort;
-  };
-
-  # Pass the whole grid configuration to the module and let it take what it
-  # wants.
-  "staging002" = import ./staging002.nix cfg;
 }
diff --git a/morph/make-grid.nix b/morph/make-grid.nix
new file mode 100644
index 0000000000000000000000000000000000000000..60d80aae1053119a0731af563290582409da9b9b
--- /dev/null
+++ b/morph/make-grid.nix
@@ -0,0 +1,27 @@
+# Define a function for making a morph configuration for a storage grid.  It
+# takes two arguments.  A string like "Production" giving the name of the grid
+# and a function that takes the grid configuration as an argument and returns
+# a set of nodes specifying the addresses and NixOS configurations for each
+# server in the morph network.
+{ name, nodes }:
+let
+  # Pin the deployment package-set to a specific version of nixpkgs.  This is
+  # NixOS 19.03 as of Aug 28 2019.  There's nothing special about it.  It's
+  # just recent at the time of development.  It can be upgraded when there is
+  # value in doing so.  Meanwhile, our platform doesn't shift around beneath
+  # us in surprising ways as time passes.
+  pkgs = import (builtins.fetchTarball {
+    url = "https://github.com/NixOS/nixpkgs/archive/3c83ad6ac13b67101cc3e2e07781963a010c1624.tar.gz";
+    sha256 = "0cdq342wrkvkyccygpp1gvwp7hhqg68hljjwld4vjixm901ayy14";
+  }) {};
+  # Load our JSON configuration for later use.
+  cfg = pkgs.lib.trivial.importJSON ./grid.config.json;
+in
+{
+  network =  {
+    # Make all of the hosts in this network use the nixpkgs we pinned above.
+    inherit pkgs;
+    # This is just for human consumption as far as I can tell.
+    description = "PrivateStorage.io ${name} Grid";
+  };
+} // (nodes cfg)
diff --git a/morph/testing-grid.nix b/morph/testing-grid.nix
new file mode 100644
index 0000000000000000000000000000000000000000..c58cefa4de516178c6619a26228cfd53473443a0
--- /dev/null
+++ b/morph/testing-grid.nix
@@ -0,0 +1,15 @@
+# Load the helper function and call it with arguments tailored for the testing
+# grid.  It will make the morph configuration for us.  We share this function
+# with the production grid and have one fewer possible point of divergence.
+import ./make-grid.nix {
+  name = "Testing";
+  nodes = cfg: {
+    "testing000" = import ./testing000.nix {
+      publicIPv4 = "3.123.26.90";
+      # Pass along some of the Tahoe-LAFS configuration.  If we have much more
+      # configuration than this we may want to keep it bundled up in one value
+      # instead of pulling individual values out to pass along.
+      inherit (cfg) publicStoragePort;
+    };
+  };
+}