diff --git a/src/main/java/gov/usgs/earthquake/nshmp/netcdf/data/NetcdfShape.java b/src/main/java/gov/usgs/earthquake/nshmp/netcdf/data/NetcdfShape.java
index 632de5c87c400353264b900a85162704e9258afb..698207bf4ae2a9d5c1c4cd5b24ad11ac491a8633 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/netcdf/data/NetcdfShape.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/netcdf/data/NetcdfShape.java
@@ -1,8 +1,13 @@
 package gov.usgs.earthquake.nshmp.netcdf.data;
 
-import java.util.Arrays;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 /**
  * Create NetCDF shapes and keep track of indices.
@@ -17,26 +22,91 @@ public class NetcdfShape {
     indexMap = builder.indexMap;
   }
 
-  public int[] buildShape(IndexMap... sizes) {
-    int[] shape = new int[indexMap.size()];
-    Arrays.fill(shape, 0);
-
-    Arrays.stream(sizes).forEach(size -> {
-      shape[indexMap.get(size.indexKey)] = size.size;
-    });
+  /**
+   * Returns builder to build a NetCDF shape.
+   */
+  public static Builder builder() {
+    return new Builder();
+  }
 
-    return shape;
+  /**
+   * Returns a builder to build an array shape for NetCDF origin and shapes.
+   */
+  public BuildShape buildShape() {
+    return new BuildShape();
   }
 
-  public static Builder builder() {
-    return new Builder();
+  public class BuildShape {
+    List<KeySize> keySizes;
+    Optional<Integer> pad = Optional.empty();
+    boolean reduce = false;
+
+    private BuildShape() {
+      keySizes = new ArrayList<>();
+    }
+
+    /**
+     * Add key and associated size for shape.
+     *
+     * @param key The key
+     * @param size The size
+     */
+    public BuildShape add(IndexKey key, int size) {
+      checkState(indexMap.containsKey(key), String.format("Key [%s] not found in shape", key));
+      keySizes.add(new KeySize(key, size));
+      return this;
+    }
+
+    /**
+     * Change to padding value of 0.
+     *
+     * Not used if reducing shape.
+     *
+     * @param value The value to pad the array shape
+     */
+    public BuildShape pad(int value) {
+      pad = Optional.of(value);
+      return this;
+    }
+
+    /**
+     * Reduce the array to only added keys in builder.
+     */
+    public BuildShape reduce() {
+      reduce = true;
+      return this;
+    }
+
+    /**
+     * Returns the shape array.
+     */
+    public int[] build() {
+      if (reduce) {
+        var reducePad = -1;
+        return build(reducePad).stream()
+            .mapToInt(Integer::intValue)
+            .filter(val -> val != reducePad)
+            .toArray();
+      } else {
+        return build(pad.orElse(0)).stream().mapToInt(Integer::intValue).toArray();
+      }
+    }
+
+    private List<Integer> build(int pad) {
+      var shape = new ArrayList<>(Collections.nCopies(indexMap.size(), pad));
+      keySizes.forEach(keySize -> {
+        shape.set(indexMap.get(keySize.indexKey), keySize.size);
+      });
+
+      return shape;
+    }
   }
 
-  public static class IndexMap {
+  public static class KeySize {
     public final IndexKey indexKey;
     public final int size;
 
-    public IndexMap(IndexKey indexKey, int size) {
+    private KeySize(IndexKey indexKey, int size) {
       this.indexKey = indexKey;
       this.size = size;
     }