diff --git a/api/client.go b/api/client.go
index 2c83ad2af5a5bd43f43b76ebf84e0eedccae57aa..55d41946a23930d0155d60a9912ed43744fc65fc 100644
--- a/api/client.go
+++ b/api/client.go
@@ -23,6 +23,7 @@ import (
 	"gitlab.com/elixxir/comms/client"
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/fastRNG"
+	"gitlab.com/elixxir/primitives/version"
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/crypto/signature/rsa"
@@ -79,10 +80,16 @@ func NewClient(ndfJSON, storageDir string, password []byte, registrationCode str
 
 	protoUser := createNewUser(rngStream, cmixGrp, e2eGrp)
 
+	// Get current client version
+	currentVersion, err := version.ParseVersion(SEMVER)
+	if err != nil {
+		return errors.WithMessage(err, "Could not parse version string.")
+	}
+
 	// Create Storage
 	passwordStr := string(password)
 	storageSess, err := storage.New(storageDir, passwordStr, protoUser,
-		cmixGrp, e2eGrp, rngStreamGen)
+		currentVersion, cmixGrp, e2eGrp, rngStreamGen)
 	if err != nil {
 		return err
 	}
@@ -124,10 +131,16 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [
 
 	protoUser := createPrecannedUser(precannedID, rngStream, cmixGrp, e2eGrp)
 
+	// Get current client version
+	currentVersion, err := version.ParseVersion(SEMVER)
+	if err != nil {
+		return errors.WithMessage(err, "Could not parse version string.")
+	}
+
 	// Create Storage
 	passwordStr := string(password)
 	storageSess, err := storage.New(storageDir, passwordStr, protoUser,
-		cmixGrp, e2eGrp, rngStreamGen)
+		currentVersion, cmixGrp, e2eGrp, rngStreamGen)
 	if err != nil {
 		return err
 	}
@@ -151,12 +164,18 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [
 func OpenClient(storageDir string, password []byte, parameters params.Network) (*Client, error) {
 	jww.INFO.Printf("OpenClient()")
 	// Use fastRNG for RNG ops (AES fortuna based RNG using system RNG)
-	rngStreamGen := fastRNG.NewStreamGenerator(12, 3,
-		csprng.NewSystemRNG)
+	rngStreamGen := fastRNG.NewStreamGenerator(12, 3, csprng.NewSystemRNG)
+
+	// Get current client version
+	currentVersion, err := version.ParseVersion(SEMVER)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Could not parse version string.")
+	}
 
 	// Load Storage
 	passwordStr := string(password)
-	storageSess, err := storage.Load(storageDir, passwordStr, rngStreamGen)
+	storageSess, err := storage.Load(storageDir, passwordStr, currentVersion,
+		rngStreamGen)
 	if err != nil {
 		return nil, err
 	}
diff --git a/storage/clientVersion/store.go b/storage/clientVersion/store.go
new file mode 100644
index 0000000000000000000000000000000000000000..344b138bd8cf328bfa17722bce8bec8c6fbfd860
--- /dev/null
+++ b/storage/clientVersion/store.go
@@ -0,0 +1,117 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package clientVersion
+
+import (
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/primitives/version"
+	"sync"
+	"time"
+)
+
+const (
+	prefix       = "clientVersionStore"
+	storeKey     = "clientVersion"
+	storeVersion = 0
+)
+
+// Store stores the version of the client's storage.
+type Store struct {
+	version version.Version
+	kv      *versioned.KV
+	sync.RWMutex
+}
+
+// NewStore returns a new clientVersion store.
+func NewStore(newVersion version.Version, kv *versioned.KV) (*Store, error) {
+	s := &Store{
+		version: newVersion,
+		kv:      kv.Prefix(prefix),
+	}
+
+	return s, s.save()
+}
+
+// LoadStore loads the clientVersion storage object.
+func LoadStore(kv *versioned.KV) (*Store, error) {
+	s := &Store{
+		kv: kv.Prefix(prefix),
+	}
+
+	obj, err := s.kv.Get(storeKey)
+	if err != nil {
+		return nil, err
+	}
+
+	s.version, err = version.ParseVersion(string(obj.Data))
+	if err != nil {
+		return nil, errors.Errorf("failed to parse client version: %+v", err)
+	}
+
+	return s, nil
+}
+
+// Get returns the stored version.
+func (s *Store) Get() version.Version {
+	s.RLock()
+	defer s.RUnlock()
+
+	return s.version
+}
+
+// CheckUpdateRequired determines if the storage needs to be upgraded to the new
+// client version. It returns true if an update is required (new > stored) and
+// false otherwise. The old stored version is returned to be used to determine
+// how to upgrade storage. If the new version is older than the stored version,
+// an error is returned.
+func (s *Store) CheckUpdateRequired(newVersion version.Version) (bool, version.Version, error) {
+	s.Lock()
+	defer s.Unlock()
+
+	oldVersion := s.version
+	diff := version.Cmp(oldVersion, newVersion)
+
+	switch {
+	case diff < 0:
+		return true, oldVersion, s.update(newVersion)
+	case diff > 0:
+		return false, oldVersion, errors.Errorf("new version (%s) is older "+
+			"than stored version (%s).", &newVersion, &oldVersion)
+	default:
+		return false, oldVersion, nil
+	}
+}
+
+// update replaces the current version with the new version if it is newer. Note
+// that this function does not take a lock.
+func (s *Store) update(newVersion version.Version) error {
+	jww.DEBUG.Printf("Updating stored client version from %s to %s.",
+		&s.version, &newVersion)
+
+	// Update version
+	s.version = newVersion
+
+	// Save new version to storage
+	return s.save()
+}
+
+// save stores the clientVersion store. Note that this function does not take
+// a lock.
+func (s *Store) save() error {
+	timeNow := time.Now()
+
+	obj := versioned.Object{
+		Version:   storeVersion,
+		Timestamp: timeNow,
+		Data:      []byte(s.version.String()),
+	}
+
+	return s.kv.Set(storeKey, &obj)
+}
diff --git a/storage/clientVersion/store_test.go b/storage/clientVersion/store_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8ff38a27599f2d43b8576e97a58e0843192bb814
--- /dev/null
+++ b/storage/clientVersion/store_test.go
@@ -0,0 +1,237 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright © 2020 xx network SEZC                                          //
+//                                                                           //
+// Use of this source code is governed by a license that can be found in the //
+// LICENSE file                                                              //
+///////////////////////////////////////////////////////////////////////////////
+
+package clientVersion
+
+import (
+	"gitlab.com/elixxir/client/storage/versioned"
+	"gitlab.com/elixxir/ekv"
+	"gitlab.com/elixxir/primitives/version"
+	"reflect"
+	"strings"
+	"testing"
+	"time"
+)
+
+// Happy path.
+func TestNewStore(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	expected := &Store{
+		version: version.New(42, 43, "44"),
+		kv:      kv.Prefix(prefix),
+	}
+
+	test, err := NewStore(expected.version, kv)
+	if err != nil {
+		t.Errorf("NewStore() returned an error: %+v", err)
+	}
+
+	if !reflect.DeepEqual(expected, test) {
+		t.Errorf("NewStore() failed to return the expected Store."+
+			"\nexpected: %+v\nreceived: %+v", expected, test)
+	}
+}
+
+// Happy path.
+func TestLoadStore(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	ver := version.New(1, 2, "3A")
+
+	expected := &Store{
+		version: ver,
+		kv:      kv.Prefix(prefix),
+	}
+	err := expected.save()
+	if err != nil {
+		t.Fatalf("Failed to save Store: %+v", err)
+	}
+
+	test, err := LoadStore(kv)
+	if err != nil {
+		t.Errorf("LoadStore() returned an error: %+v", err)
+	}
+
+	if !reflect.DeepEqual(expected, test) {
+		t.Errorf("LoadStore() failed to return the expected Store."+
+			"\nexpected: %+v\nreceived: %+v", expected, test)
+	}
+}
+
+// Error path: an error is returned when the loaded Store has an invalid version
+// that fails to be parsed.
+func TestLoadStore_ParseVersionError(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	obj := versioned.Object{
+		Version:   storeVersion,
+		Timestamp: time.Now(),
+		Data:      []byte("invalid version"),
+	}
+
+	err := kv.Prefix(prefix).Set(storeKey, &obj)
+	if err != nil {
+		t.Fatalf("Failed to save Store: %+v", err)
+	}
+
+	_, err = LoadStore(kv)
+	if err == nil || !strings.Contains(err.Error(), "failed to parse client version") {
+		t.Errorf("LoadStore() did not return an error when the client version "+
+			"is invalid: %+v", err)
+	}
+}
+
+// Happy path.
+func TestStore_Get(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	expected := version.New(1, 2, "3A")
+
+	s := &Store{
+		version: expected,
+		kv:      kv.Prefix(prefix),
+	}
+
+	test := s.Get()
+	if !reflect.DeepEqual(expected, test) {
+		t.Errorf("Get() failed to return the expected version."+
+			"\nexpected: %s\nreceived: %s", &expected, &test)
+	}
+}
+
+// Happy path.
+func TestStore_CheckUpdateRequired(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	storedVersion := version.New(1, 2, "3")
+	newVersion := version.New(2, 3, "4")
+	s, err := NewStore(storedVersion, kv)
+	if err != nil {
+		t.Fatalf("Failed to generate a new Store: %+v", err)
+	}
+
+	updateRequired, oldVersion, err := s.CheckUpdateRequired(newVersion)
+	if err != nil {
+		t.Errorf("CheckUpdateRequired() returned an error: %+v", err)
+	}
+
+	if !updateRequired {
+		t.Errorf("CheckUpdateRequired() did not indicate that an update is "+
+			"required when the new Version (%s) is newer than the stored"+
+			"version (%s)", &newVersion, &storedVersion)
+	}
+
+	if !version.Equal(storedVersion, oldVersion) {
+		t.Errorf("CheckUpdateRequired() did return the expected old Version."+
+			"\nexpected: %s\nreceived: %s", &storedVersion, &oldVersion)
+	}
+}
+
+// Happy path: the new version is equal to the stored version.
+func TestStore_CheckUpdateRequired_EqualVersions(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	storedVersion := version.New(2, 3, "3")
+	newVersion := version.New(2, 3, "4")
+	s, err := NewStore(storedVersion, kv)
+	if err != nil {
+		t.Fatalf("Failed to generate a new Store: %+v", err)
+	}
+
+	updateRequired, oldVersion, err := s.CheckUpdateRequired(newVersion)
+	if err != nil {
+		t.Errorf("CheckUpdateRequired() returned an error: %+v", err)
+	}
+
+	if updateRequired {
+		t.Errorf("CheckUpdateRequired() did not indicate that an update is required "+
+			"when the new Version (%s) is equal to the stored version (%s)",
+			&newVersion, &storedVersion)
+	}
+
+	if !version.Equal(storedVersion, oldVersion) {
+		t.Errorf("CheckUpdateRequired() did return the expected old Version."+
+			"\nexpected: %s\nreceived: %s", &storedVersion, &oldVersion)
+	}
+}
+
+// Error path: new version is older than stored version.
+func TestStore_CheckUpdateRequired_NewVersionTooOldError(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	storedVersion := version.New(2, 3, "4")
+	newVersion := version.New(1, 2, "3")
+	s, err := NewStore(storedVersion, kv)
+	if err != nil {
+		t.Fatalf("Failed to generate a new Store: %+v", err)
+	}
+
+	updateRequired, oldVersion, err := s.CheckUpdateRequired(newVersion)
+	if err == nil || !strings.Contains(err.Error(), "older than stored version") {
+		t.Errorf("CheckUpdateRequired() did not return an error when the new version "+
+			"is older than the stored version: %+v", err)
+	}
+
+	if updateRequired {
+		t.Errorf("CheckUpdateRequired() indicated that an update is required when the "+
+			"new Version (%s) is older than the stored version (%s)",
+			&newVersion, &storedVersion)
+	}
+
+	if !version.Equal(storedVersion, oldVersion) {
+		t.Errorf("CheckUpdateRequired() did return the expected old Version."+
+			"\nexpected: %s\nreceived: %s", &storedVersion, &oldVersion)
+	}
+}
+
+// Happy path.
+func TestStore_update(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	ver1 := version.New(1, 2, "3A")
+	ver2 := version.New(1, 5, "patch5")
+
+	s := &Store{
+		version: ver1,
+		kv:      kv.Prefix(prefix),
+	}
+
+	err := s.update(ver2)
+	if err != nil {
+		t.Errorf("Update() returned an error: %+v", err)
+	}
+
+	if !reflect.DeepEqual(ver2, s.version) {
+		t.Errorf("Update() did not set the correct version."+
+			"\nexpected: %s\nreceived: %s", &ver2, &s.version)
+	}
+}
+
+// Happy path.
+func TestStore_save(t *testing.T) {
+	kv := versioned.NewKV(make(ekv.Memstore))
+	ver := version.New(1, 2, "3A")
+
+	s := &Store{
+		version: ver,
+		kv:      kv.Prefix(prefix),
+	}
+
+	err := s.save()
+	if err != nil {
+		t.Errorf("save() returned an error: %+v", err)
+	}
+
+	obj, err := s.kv.Get(storeKey)
+	if err != nil {
+		t.Errorf("Failed to load clientVersion store: %+v", err)
+	}
+
+	if ver.String() != string(obj.Data) {
+		t.Errorf("Failed to get correct data from stored object."+
+			"\nexpected: %s\nreceived: %s", ver.String(), obj.Data)
+	}
+
+	if storeVersion != obj.Version {
+		t.Errorf("Failed to get correct version from stored object."+
+			"\nexpected: %d\nreceived: %d", storeVersion, obj.Version)
+	}
+
+}
diff --git a/storage/session.go b/storage/session.go
index de3768d13e941592da584439a3c15b1d38899a8c..698d1e295e78913596935f25dd1adbe3fda3732b 100644
--- a/storage/session.go
+++ b/storage/session.go
@@ -14,6 +14,7 @@ import (
 	"gitlab.com/elixxir/client/globals"
 	userInterface "gitlab.com/elixxir/client/interfaces/user"
 	"gitlab.com/elixxir/client/storage/auth"
+	"gitlab.com/elixxir/client/storage/clientVersion"
 	"gitlab.com/elixxir/client/storage/cmix"
 	"gitlab.com/elixxir/client/storage/conversation"
 	"gitlab.com/elixxir/client/storage/e2e"
@@ -25,6 +26,7 @@ import (
 	"gitlab.com/elixxir/crypto/cyclic"
 	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/elixxir/ekv"
+	"gitlab.com/elixxir/primitives/version"
 	"gitlab.com/xx_network/crypto/csprng"
 	"gitlab.com/xx_network/crypto/large"
 	"gitlab.com/xx_network/crypto/signature/rsa"
@@ -57,6 +59,7 @@ type Session struct {
 	criticalRawMessages *utility.CmixMessageBuffer
 	garbledMessages     *utility.MeteredCmixMessageBuffer
 	reception           *reception.Store
+	clientVersion       *clientVersion.Store
 }
 
 // Initialize a new Session object
@@ -76,9 +79,8 @@ func initStore(baseDir, password string) (*Session, error) {
 }
 
 // Creates new UserData in the session
-
-func New(baseDir, password string, u userInterface.User, cmixGrp,
-	e2eGrp *cyclic.Group, rng *fastRNG.StreamGenerator) (*Session, error) {
+func New(baseDir, password string, u userInterface.User, currentVersion version.Version,
+	cmixGrp, e2eGrp *cyclic.Group, rng *fastRNG.StreamGenerator) (*Session, error) {
 
 	s, err := initStore(baseDir, password)
 	if err != nil {
@@ -132,11 +134,18 @@ func New(baseDir, password string, u userInterface.User, cmixGrp,
 
 	s.reception = reception.NewStore(s.kv)
 
+	s.clientVersion, err = clientVersion.NewStore(currentVersion, s.kv)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to create client version store.")
+	}
+
 	return s, nil
 }
 
 // Loads existing user data into the session
-func Load(baseDir, password string, rng *fastRNG.StreamGenerator) (*Session, error) {
+func Load(baseDir, password string, currentVersion version.Version,
+	rng *fastRNG.StreamGenerator) (*Session, error) {
+
 	s, err := initStore(baseDir, password)
 	if err != nil {
 		return nil, errors.WithMessage(err, "Failed to load Session")
@@ -147,6 +156,17 @@ func Load(baseDir, password string, rng *fastRNG.StreamGenerator) (*Session, err
 		return nil, errors.WithMessage(err, "Failed to load Session")
 	}
 
+	s.clientVersion, err = clientVersion.LoadStore(s.kv)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to load client version store.")
+	}
+
+	// Determine if the storage needs to be updated to the current version
+	_, _, err = s.clientVersion.CheckUpdateRequired(currentVersion)
+	if err != nil {
+		return nil, errors.WithMessage(err, "Failed to load client version store.")
+	}
+
 	s.user, err = user.LoadUser(s.kv)
 	if err != nil {
 		return nil, errors.WithMessage(err, "Failed to load Session")
@@ -241,6 +261,13 @@ func (s *Session) GetGarbledMessages() *utility.MeteredCmixMessageBuffer {
 	return s.garbledMessages
 }
 
+// GetClientVersion returns the version of the client storage.
+func (s *Session) GetClientVersion() version.Version {
+	s.mux.RLock()
+	defer s.mux.RUnlock()
+	return s.clientVersion.Get()
+}
+
 func (s *Session) Conversations() *conversation.Store {
 	s.mux.RLock()
 	defer s.mux.RUnlock()
@@ -307,11 +334,11 @@ func InitTestingSession(i interface{}) *Session {
 			"3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71"+
 			"BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0"+
 			"DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", 16))
-	cmix, err := cmix.NewStore(cmixGrp, kv, cmixGrp.NewInt(2))
+	cmixStore, err := cmix.NewStore(cmixGrp, kv, cmixGrp.NewInt(2))
 	if err != nil {
 		globals.Log.FATAL.Panicf("InitTestingSession failed to create dummy cmix session: %+v", err)
 	}
-	s.cmix = cmix
+	s.cmix = cmixStore
 
 	e2eStore, err := e2e.NewStore(cmixGrp, kv, cmixGrp.NewInt(2), uid,
 		fastRNG.NewStreamGenerator(7, 3, csprng.NewSystemRNG))