diff --git a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java
index d34e167e16a6df0a2af19562f6c6ff59785ea6ea..921cce17f15e4bcae871255cb0aa8bc86cf49b27 100644
--- a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java
+++ b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java
@@ -9,12 +9,16 @@ import java.lang.reflect.Type;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.stream.Collectors;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.reflect.TypeToken;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -27,7 +31,9 @@ import gov.usgs.earthquake.nshmp.calc.Hazard;
 import gov.usgs.earthquake.nshmp.calc.HazardCalcs;
 import gov.usgs.earthquake.nshmp.calc.Site;
 import gov.usgs.earthquake.nshmp.data.XySequence;
-import gov.usgs.earthquake.nshmp.model.NshmTests.Nshm;
+import gov.usgs.earthquake.nshmp.gmm.Imt;
+
+import io.swagger.v3.core.util.Yaml;
 
 /**
  * Utilities to run tests on a NSHM.
@@ -42,16 +48,28 @@ class NshmTestUtils {
       .create();
 
   /**
-   * Generate results for all {@link NSHM}s
+   * Load a model.
    *
-   * Run "./gradlew nshms" to first download all NSHMs
+   * @param nshm The NSHM
    */
-  public static void main(String[] args) throws IOException {
-    for (Nshm nshm : Nshm.values()) {
-      /* Initialize and shut down executor to generate results. */
-      NshmModel nshmModel = loadModel(nshm);
-      writeExpecteds(nshmModel);
-      nshmModel.exec.shutdown();
+  static NshmModel loadModel(Nshm nshm) {
+    int cores = Runtime.getRuntime().availableProcessors();
+
+    return new NshmModel(
+        nshm,
+        ModelLoader.load(nshm.modelPath()),
+        Executors.newFixedThreadPool(cores));
+  }
+
+  /**
+   * Read in nshms.yml file.
+   */
+  static NshmConfig readNshms() {
+    try {
+      JsonNode jsonNode = Yaml.mapper().readValue(Paths.get("nshms.yml").toFile(), JsonNode.class);
+      return GSON.fromJson(jsonNode.toString(), NshmConfig.class);
+    } catch (Exception e) {
+      throw new RuntimeException("Failed to read and parse nshms.yml file");
     }
   }
 
@@ -60,7 +78,7 @@ class NshmTestUtils {
    *
    * @param nshm The NSHM to test
    */
-  static final void testNshm(Nshm nshm) {
+  static void testNshm(Nshm nshm) {
     NshmModel nshmModel = loadModel(nshm);
 
     for (NamedLocation location : nshm.locations()) {
@@ -70,6 +88,19 @@ class NshmTestUtils {
     nshmModel.exec.shutdown();
   }
 
+  /**
+   * Write expected values
+   *
+   * @param nshmModel The NSHM model
+   */
+  static void writeExpecteds(NshmModel nshmModel) throws IOException {
+    for (NamedLocation location : nshmModel.nshm.locations()) {
+      Map<String, XySequence> xyMap = generateActual(nshmModel, location);
+      String json = GSON.toJson(xyMap);
+      writeExpected(nshmModel.nshm, location, json);
+    }
+  }
+
   private static void assertCurveEquals(XySequence expected, XySequence actual, double tol) {
     // IMLs close but not exact due to exp() transform
     assertArrayEquals(
@@ -129,15 +160,6 @@ class NshmTestUtils {
     return xyMap;
   }
 
-  private static NshmModel loadModel(Nshm nshm) {
-    int cores = Runtime.getRuntime().availableProcessors();
-
-    return new NshmModel(
-        nshm,
-        ModelLoader.load(nshm.modelPath()),
-        Executors.newFixedThreadPool(cores));
-  }
-
   private static Map<String, XySequence> readExpected(NshmModel nshmModel, NamedLocation loc) {
     Path resultPath = DATA_PATH
         .resolve(nshmModel.nshm.modelName())
@@ -159,14 +181,6 @@ class NshmTestUtils {
     return xyMap;
   }
 
-  private static void writeExpecteds(NshmModel nshmModel) throws IOException {
-    for (NamedLocation location : nshmModel.nshm.locations()) {
-      Map<String, XySequence> xyMap = generateActual(nshmModel, location);
-      String json = GSON.toJson(xyMap);
-      writeExpected(nshmModel.nshm, location, json);
-    }
-  }
-
   private static void writeExpected(
       Nshm nshm,
       NamedLocation loc,
@@ -201,4 +215,63 @@ class NshmTestUtils {
       this.exec = exec;
     }
   }
+
+  static class NshmInfo {
+    final String repo;
+    final String tag;
+    final int year;
+
+    NshmInfo(String repo, String tag, int year) {
+      this.repo = repo;
+      this.tag = tag;
+      this.year = year;
+    }
+  }
+
+  static class NshmConfig {
+    NshmInfo[] nshms;
+
+    NshmInfo nshm(String repo, int year) {
+      return Arrays.stream(nshms)
+          .filter(nshm -> nshm.repo == repo && nshm.year == year)
+          .findFirst()
+          .orElseThrow();
+    }
+  }
+
+  static class Nshm {
+    private final NshmInfo nshmInfo;
+    private final List<NamedLocation> locations;
+    private final Set<Imt> imts;
+
+    Nshm(NshmInfo nshmInfo, List<NamedLocation> locations, Set<Imt> imts) {
+      this.nshmInfo = nshmInfo;
+      this.locations = locations;
+      this.imts = imts;
+    }
+
+    Path modelPath() {
+      return Paths.get("nshms", modelName());
+    }
+
+    String modelName() {
+      return String.format("%s-%s", nshmInfo.repo, nshmInfo.year);
+    }
+
+    List<NamedLocation> locations() {
+      return List.copyOf(locations);
+    }
+
+    Set<Imt> imts() {
+      return Set.copyOf(imts);
+    }
+
+    int year() {
+      return nshmInfo.year;
+    }
+
+    String resultFilename(NamedLocation location) {
+      return String.format("%s-%s-%s.json", modelName(), year(), location.name());
+    }
+  }
 }
diff --git a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTests.java b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTests.java
index e430ee8a60d2a288376dbf2dcac0e41f07bb411c..bb122bab598a3394640624cda37e24af62b54fcd 100644
--- a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTests.java
+++ b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTests.java
@@ -1,16 +1,20 @@
 package gov.usgs.earthquake.nshmp.model;
 
 import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
+import java.util.ArrayList;
 import java.util.EnumSet;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import org.junit.jupiter.api.Test;
 
 import gov.usgs.earthquake.nshmp.NamedLocation;
 import gov.usgs.earthquake.nshmp.gmm.Imt;
+import gov.usgs.earthquake.nshmp.model.NshmTestUtils.Nshm;
+import gov.usgs.earthquake.nshmp.model.NshmTestUtils.NshmInfo;
+import gov.usgs.earthquake.nshmp.model.NshmTestUtils.NshmModel;
 import gov.usgs.earthquake.nshmp.site.NshmpSite;
 
 /**
@@ -45,6 +49,51 @@ class NshmTests {
 
   private static final Set<Imt> IMTS = EnumSet.of(Imt.PGA, Imt.SA0P2, Imt.SA1P0, Imt.SA5P0);
 
+  private static final Map<String, Nshm> NSHMS;
+
+  static {
+    Map<String, Nshm> nshms = new HashMap<>();
+
+    for (NshmInfo nshmInfo : NshmTestUtils.readNshms().nshms) {
+      List<NamedLocation> locations = new ArrayList<>();
+
+      switch (nshmInfo.repo) {
+        case "nshm-conus": {
+          locations = CONUS_LOCATIONS;
+          break;
+        }
+        case "nshm-alaska": {
+          locations = ALASKA_LOCATIONS;
+          break;
+        }
+        case "nshm-hawaii": {
+          locations = HAWAII_LOCATIONS;
+          break;
+        }
+        default:
+          throw new RuntimeException(nshmInfo.repo + " not supported");
+      }
+
+      nshms.put(nshmInfo.repo + "-" + nshmInfo.year, new Nshm(nshmInfo, locations, IMTS));
+    }
+
+    NSHMS = nshms;
+  }
+
+  /**
+   * Generate results for all {@link NSHM}s
+   *
+   * Run "./gradlew nshms" to first download all NSHMs
+   */
+  public static void main(String[] args) throws IOException {
+    for (Nshm nshm : NSHMS.values()) {
+      /* Initialize and shut down executor to generate results. */
+      NshmModel nshmModel = NshmTestUtils.loadModel(nshm);
+      NshmTestUtils.writeExpecteds(nshmModel);
+      nshmModel.exec.shutdown();
+    }
+  }
+
   /**
    * Test Alaska 2023 NSHM, {@link Nshm.ALASKA_2023}.
    *
@@ -52,7 +101,7 @@ class NshmTests {
    */
   @Test
   final void testAlaska2023() throws IOException {
-    NshmTestUtils.testNshm(Nshm.ALASKA_2023);
+    NshmTestUtils.testNshm(NSHMS.get("nshm-alaska-2023"));
   }
 
   /**
@@ -62,7 +111,7 @@ class NshmTests {
    */
   @Test
   final void testConus2018() throws IOException {
-    NshmTestUtils.testNshm(Nshm.CONUS_2018);
+    NshmTestUtils.testNshm(NSHMS.get("nshm-conus-2018"));
   }
 
   /**
@@ -72,7 +121,7 @@ class NshmTests {
    */
   @Test
   final void testConus2023() throws IOException {
-    NshmTestUtils.testNshm(Nshm.CONUS_2023);
+    NshmTestUtils.testNshm(NSHMS.get("nshm-conus-2023"));
   }
 
   /**
@@ -82,50 +131,6 @@ class NshmTests {
    */
   @Test
   final void testHawaii2021() throws IOException {
-    NshmTestUtils.testNshm(Nshm.HAWAII_2021);
-  }
-
-  static enum Nshm {
-    ALASKA_2023("nshm-alaska-3.a.0", ALASKA_LOCATIONS, IMTS),
-
-    CONUS_2018("nshm-conus-5.2.0", CONUS_LOCATIONS, IMTS),
-
-    CONUS_2023("nshm-conus-6.a.3", CONUS_LOCATIONS, IMTS),
-
-    HAWAII_2021("nshm-hawaii-2.0.2", HAWAII_LOCATIONS, IMTS);
-
-    private final String modelName;
-    private final List<NamedLocation> locations;
-    private final Set<Imt> imts;
-
-    Nshm(String modelName, List<NamedLocation> locations, Set<Imt> imts) {
-      this.locations = locations;
-      this.imts = imts;
-      this.modelName = modelName;
-    }
-
-    Path modelPath() {
-      return Paths.get("nshms", modelName);
-    }
-
-    String modelName() {
-      return modelName;
-    }
-
-    List<NamedLocation> locations() {
-      return List.copyOf(locations);
-    }
-
-    Set<Imt> imts() {
-      return Set.copyOf(imts);
-    }
-
-    int year() {
-      return Integer.parseInt(name().split("_")[1]);
-    }
-
-    String resultFilename(NamedLocation location) {
-      return String.format("%s-%s-%s.json", modelName, year(), location.name());
-    }
+    NshmTestUtils.testNshm(NSHMS.get("nshm-hawaii-2021"));
   }
 }