diff --git a/api/client.go b/api/client.go
index d1b864acbf58886d8c4a4fe5605d32787ad2b487..5bbad8f8c76dbcafc87b9f50955339a5decaa5d2 100644
--- a/api/client.go
+++ b/api/client.go
@@ -219,7 +219,7 @@ func Login(storageDir string, password []byte, parameters params.Network) (*Clie
 	}
 
 	//get the NDF to pass into permissioning and the network manager
-	def := c.storage.GetBaseNDF()
+	def := c.storage.GetNDF()
 
 	//initialize permissioning
 	if def.Registration.Address != "" {
@@ -286,7 +286,7 @@ func LoginWithNewBaseNDF_UNSAFE(storageDir string, password []byte,
 	}
 
 	//store the updated base NDF
-	c.storage.SetBaseNDF(def)
+	c.storage.SetNDF(def)
 
 	//initialize permissioning
 	if def.Registration.Address != "" {
@@ -622,7 +622,7 @@ func checkVersionAndSetupStorage(def *ndf.NetworkDefinition, storageDir string,
 	}
 
 	// Save NDF to be used in the future
-	storageSess.SetBaseNDF(def)
+	storageSess.SetNDF(def)
 
 	if !isPrecanned {
 		//store the registration code for later use
diff --git a/network/follow.go b/network/follow.go
index aa505deecbb5cda93f1ebed0124ef070cf234705..3d5d8734b83c5892aae387e55e9e4ab6dba23e38 100644
--- a/network/follow.go
+++ b/network/follow.go
@@ -159,6 +159,7 @@ func (m *manager) follow(report interfaces.ClientErrorReport, rng csprng.Source,
 
 		// update gateway connections
 		m.GetSender().UpdateNdf(m.GetInstance().GetPartialNdf().Get())
+		m.Session.SetNDF(m.GetInstance().GetPartialNdf().Get())
 	}
 
 	// Update the address space size
diff --git a/network/gateway/hostPool.go b/network/gateway/hostPool.go
index 6b27cb9d1e3f3b491efa05fc52f3256b9324f587..1447608bfcc825f5e1269b2941d617718461662d 100644
--- a/network/gateway/hostPool.go
+++ b/network/gateway/hostPool.go
@@ -13,7 +13,6 @@ package gateway
 
 import (
 	"encoding/binary"
-	"fmt"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/storage"
@@ -115,8 +114,24 @@ func newHostPool(poolParams PoolParams, rng *fastRNG.StreamGenerator, ndf *ndf.N
 		return nil, err
 	}
 
+	// Get the last used list of hosts and use it to seed the host pool list
+	hostList, err := storage.HostList().Get()
+	numHostsAdded := 0
+	if err == nil {
+		for _, hid := range hostList {
+			err := result.replaceHostNoStore(hid, uint32(numHostsAdded))
+			if err != nil {
+				jww.WARN.Printf("Unable to add stored host %s: %s", hid, err.Error())
+			} else {
+				numHostsAdded++
+			}
+		}
+	} else {
+		jww.WARN.Printf("Building new HostPool because no HostList stored: %+v", err)
+	}
+
 	// Build the initial HostPool and return
-	for i := 0; i < len(result.hostList); i++ {
+	for i := numHostsAdded; i < len(result.hostList); i++ {
 		err := result.forceReplace(uint32(i))
 		if err != nil {
 			return nil, err
@@ -279,8 +294,29 @@ func (h *HostPool) forceReplace(oldPoolIndex uint32) error {
 	}
 }
 
-// Replace the given slot in the HostPool with a new Gateway with the specified ID
+// replaceHost replaces the given slot in the HostPool with a new Gateway with
+// the specified ID. The resulting host list is saved to storage.
 func (h *HostPool) replaceHost(newId *id.ID, oldPoolIndex uint32) error {
+	err := h.replaceHostNoStore(newId, oldPoolIndex)
+	if err != nil {
+		return err
+	}
+
+	// Convert list of of non-nil and non-zero hosts to ID list
+	idList := make([]*id.ID, 0, len(h.hostList))
+	for _, host := range h.hostList {
+		if host.GetId() != nil && !host.GetId().Cmp(&id.ID{}) {
+			idList = append(idList, host.GetId())
+		}
+	}
+
+	// Save the list to storage
+	return h.storage.HostList().Store(idList)
+}
+
+// replaceHostNoStore replaces the given slot in the HostPool with a new Gateway
+// with the specified ID.
+func (h *HostPool) replaceHostNoStore(newId *id.ID, oldPoolIndex uint32) error {
 	// Obtain that GwId's Host object
 	newHost, ok := h.manager.GetHost(newId)
 	if !ok {
@@ -291,7 +327,8 @@ func (h *HostPool) replaceHost(newId *id.ID, oldPoolIndex uint32) error {
 	// Keep track of oldHost for cleanup
 	oldHost := h.hostList[oldPoolIndex]
 
-	// Use the poolIdx to overwrite the random Host in the corresponding index in the hostList
+	// Use the poolIdx to overwrite the random Host in the corresponding index
+	// in the hostList
 	h.hostList[oldPoolIndex] = newHost
 	// Use the GwId to keep track of the new random Host's index in the hostList
 	h.hostMap[*newId] = oldPoolIndex
@@ -301,7 +338,9 @@ func (h *HostPool) replaceHost(newId *id.ID, oldPoolIndex uint32) error {
 		delete(h.hostMap, *oldHost.GetId())
 		go oldHost.Disconnect()
 	}
-	jww.DEBUG.Printf("Replaced Host at %d with new Host %s", oldPoolIndex, newId.String())
+	jww.DEBUG.Printf("Replaced Host at %d with new Host %s", oldPoolIndex,
+		newId.String())
+
 	return nil
 }
 
@@ -388,7 +427,7 @@ func (h *HostPool) removeGateway(gwId *id.ID) {
 func (h *HostPool) addGateway(gwId *id.ID, ndfIndex int) {
 	gw := h.ndf.Gateways[ndfIndex]
 
-	//check if the host exists
+	// Check if the host exists
 	host, ok := h.manager.GetHost(gwId)
 	if !ok {
 
@@ -443,7 +482,7 @@ func readUint32(rng io.Reader) uint32 {
 	var rndBytes [4]byte
 	i, err := rng.Read(rndBytes[:])
 	if i != 4 || err != nil {
-		panic(fmt.Sprintf("cannot read from rng: %+v", err))
+		jww.FATAL.Panicf("cannot read from rng: %+v", err)
 	}
 	return binary.BigEndian.Uint32(rndBytes[:])
 }
diff --git a/network/gateway/hostpool_test.go b/network/gateway/hostpool_test.go
index 49dcacf6b8231647b8c0cbc0ab6e6f84b0c7d126..f88bdf49a5c02e757781f3c452b9eef2759862bb 100644
--- a/network/gateway/hostpool_test.go
+++ b/network/gateway/hostpool_test.go
@@ -54,6 +54,49 @@ func TestNewHostPool(t *testing.T) {
 	}
 }
 
+// Tests that the hosts are loaded from storage, if they exist.
+func TestNewHostPool_HostListStore(t *testing.T) {
+	manager := newMockManager()
+	rng := fastRNG.NewStreamGenerator(1, 1, csprng.NewSystemRNG)
+	testNdf := getTestNdf(t)
+	testStorage := storage.InitTestingSession(t)
+	addGwChan := make(chan network.NodeGateway)
+	params := DefaultPoolParams()
+	params.MaxPoolSize = uint32(len(testNdf.Gateways))
+
+	addedIDs := []*id.ID{
+		id.NewIdFromString("testID0", id.Gateway, t),
+		id.NewIdFromString("testID1", id.Gateway, t),
+		id.NewIdFromString("testID2", id.Gateway, t),
+		id.NewIdFromString("testID3", id.Gateway, t),
+	}
+	err := testStorage.HostList().Store(addedIDs)
+	if err != nil {
+		t.Fatalf("Failed to store host list: %+v", err)
+	}
+
+	for i, hid := range addedIDs {
+		testNdf.Gateways[i].ID = hid.Marshal()
+	}
+
+	// Call the constructor
+	hp, err := newHostPool(params, rng, testNdf, manager, testStorage, addGwChan)
+	if err != nil {
+		t.Fatalf("Failed to create mock host pool: %v", err)
+	}
+
+	// Check that the host list was saved to storage
+	hostList, err := hp.storage.HostList().Get()
+	if err != nil {
+		t.Errorf("Failed to get host list: %+v", err)
+	}
+
+	if !reflect.DeepEqual(addedIDs, hostList) {
+		t.Errorf("Failed to save expected host list to storage."+
+			"\nexpected: %+v\nreceived: %+v", addedIDs, hostList)
+	}
+}
+
 // Unit test
 func TestHostPool_ManageHostPool(t *testing.T) {
 	manager := newMockManager()
@@ -115,7 +158,7 @@ func TestHostPool_ManageHostPool(t *testing.T) {
 	for _, ndfGw := range testNdf.Gateways {
 		gwId, err := id.Unmarshal(ndfGw.ID)
 		if err != nil {
-			t.Errorf("Failed to marshal gateway id for %v", ndfGw)
+			t.Fatalf("Failed to marshal gateway id for %v", ndfGw)
 		}
 		if _, ok := testPool.hostMap[*gwId]; ok {
 			t.Errorf("Expected gateway %v to be removed from pool", gwId)
@@ -135,6 +178,7 @@ func TestHostPool_ReplaceHost(t *testing.T) {
 		hostList: make([]*connect.Host, newIndex+1),
 		hostMap:  make(map[id.ID]uint32),
 		ndf:      testNdf,
+		storage:  storage.InitTestingSession(t),
 	}
 
 	/* "Replace" a host with no entry */
@@ -228,6 +272,18 @@ func TestHostPool_ReplaceHost(t *testing.T) {
 			"\n\tReceived: %d", newIndex, retrievedIndex)
 	}
 
+	// Check that the host list was saved to storage
+	hostList, err := hostPool.storage.HostList().Get()
+	if err != nil {
+		t.Errorf("Failed to get host list: %+v", err)
+	}
+
+	expectedList := []*id.ID{gwIdTwo}
+
+	if !reflect.DeepEqual(expectedList, hostList) {
+		t.Errorf("Failed to save expected host list to storage."+
+			"\nexpected: %+v\nreceived: %+v", expectedList, hostList)
+	}
 }
 
 // Error path, could not get host
@@ -754,7 +810,7 @@ func TestHostPool_UpdateConns_RemoveGateways(t *testing.T) {
 	for _, ndfGw := range testNdf.Gateways {
 		gwId, err := id.Unmarshal(ndfGw.ID)
 		if err != nil {
-			t.Errorf("Failed to marshal gateway id for %v", ndfGw)
+			t.Fatalf("Failed to marshal gateway id for %v", ndfGw)
 		}
 		if _, ok := testPool.hostMap[*gwId]; ok {
 			t.Errorf("Expected gateway %v to be removed from pool", gwId)
diff --git a/storage/ndf.go b/storage/ndf.go
index 14cb4147b89a4fa53de52e505627c12dbd3abc15..1b081fd0f68c32b140492cc5a61b4f8052eb2134 100644
--- a/storage/ndf.go
+++ b/storage/ndf.go
@@ -13,25 +13,25 @@ import (
 	"gitlab.com/xx_network/primitives/ndf"
 )
 
-const baseNdfKey = "baseNdf"
+const ndfKey = "ndf"
 
-func (s *Session) SetBaseNDF(def *ndf.NetworkDefinition) {
-	err := utility.SaveNDF(s.kv, baseNdfKey, def)
+func (s *Session) SetNDF(def *ndf.NetworkDefinition) {
+	err := utility.SaveNDF(s.kv, ndfKey, def)
 	if err != nil {
-		jww.FATAL.Printf("Failed to dave the base NDF: %s", err)
+		jww.FATAL.Printf("Failed to dave the NDF: %+v", err)
 	}
-	s.baseNdf = def
+	s.ndf = def
 }
 
-func (s *Session) GetBaseNDF() *ndf.NetworkDefinition {
-	if s.baseNdf != nil {
-		return s.baseNdf
+func (s *Session) GetNDF() *ndf.NetworkDefinition {
+	if s.ndf != nil {
+		return s.ndf
 	}
-	def, err := utility.LoadNDF(s.kv, baseNdfKey)
+	def, err := utility.LoadNDF(s.kv, ndfKey)
 	if err != nil {
-		jww.FATAL.Printf("Could not load the base NDF: %s", err)
+		jww.FATAL.Printf("Could not load the NDF: %+v", err)
 	}
 
-	s.baseNdf = def
+	s.ndf = def
 	return def
 }
diff --git a/storage/session.go b/storage/session.go
index c2155214b5dec344da60d9e2f2d831387ccabd1b..3c4c1932baf747b080a5272b3702876abb57c652 100644
--- a/storage/session.go
+++ b/storage/session.go
@@ -51,7 +51,7 @@ type Session struct {
 
 	//memoized data
 	regStatus RegistrationStatus
-	baseNdf   *ndf.NetworkDefinition
+	ndf       *ndf.NetworkDefinition
 
 	//sub-stores
 	e2e                 *e2e.Store
@@ -414,5 +414,7 @@ func InitTestingSession(i interface{}) *Session {
 		jww.FATAL.Panicf("Failed to create uncheckRound store: %v", err)
 	}
 
+	s.hostList = hostList.NewStore(s.kv)
+
 	return s
 }