diff --git a/.gitignore b/.gitignore
index 1fc2bce8989614db73e2d0cc8f7552cbbcdc4aea..65899b422cb10044f735e8bc1c7ca91e520a8241 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,6 @@ csbi/resources/csbi
 controller/configs/testing-gosdn.toml
 controller/configs/development-gosdn.toml
 controller/configs/containerlab-gosdn.toml
+**/stores_testing
+
+config/.gosdnc.toml
diff --git a/controller/api/initialise_test.go b/controller/api/initialise_test.go
index bdd70085037ef49cedd18f19aa2ba437871e6405..a927efd228f43b7ab048bec326df6cd8b8484e59 100644
--- a/controller/api/initialise_test.go
+++ b/controller/api/initialise_test.go
@@ -80,8 +80,8 @@ func bootstrapUnitTest() {
 		log.Fatal(err)
 	}
 
-	pndStore = nucleus.NewPndStore()
-	sbiStore = nucleus.NewSbiStore(pndUUID)
+	pndStore = nucleus.NewMemoryPndStore()
+	sbiStore = nucleus.NewMemorySbiStore()
 	userService = rbacImpl.NewUserService(rbacImpl.NewMemoryUserStore())
 	roleService = rbacImpl.NewRoleService(rbacImpl.NewMemoryRoleStore())
 
diff --git a/controller/config/config.go b/controller/config/config.go
index 0defa09c32f6772c0519f27550c41a3911e3814b..ac47b954110a99ea911fc83728ab3281526e2783 100644
--- a/controller/config/config.go
+++ b/controller/config/config.go
@@ -17,6 +17,7 @@ const (
 	baseSouthBoundUUIDKey           = "baseSouthBoundUUID"
 	changeTimeoutKey                = "GOSDN_CHANGE_TIMEOUT"
 	databaseConnectionKey           = "databaseConnection"
+	filesystemPathToStores          = "filesystemPathToStores"
 )
 
 // BasePndUUID is an uuid for the base PND
@@ -37,6 +38,9 @@ var LogLevel logrus.Level
 // DatabaseConnection holds the credentials and address of the used database
 var DatabaseConnection string
 
+// FilesystemPathToStores determines in which folder the stores should be saved
+var FilesystemPathToStores = "stores_testing"
+
 // Init gets called on module import
 func Init() {
 	err := InitializeConfig()
@@ -81,6 +85,11 @@ func InitializeConfig() error {
 
 	DatabaseConnection = getStringFromViper(databaseConnectionKey)
 
+	FilesystemPathToStores = getStringFromViper(filesystemPathToStores)
+	if FilesystemPathToStores == "" {
+		FilesystemPathToStores = "stores"
+	}
+
 	return nil
 }
 
diff --git a/controller/configs/containerlab-gosdn.toml.example b/controller/configs/containerlab-gosdn.toml.example
index 0a7a31bfe8b19c0a779c42fd3d26af6737acbb35..2c5e7f28d8a88179317e17d4528afc108a5eed45 100644
--- a/controller/configs/containerlab-gosdn.toml.example
+++ b/controller/configs/containerlab-gosdn.toml.example
@@ -10,4 +10,5 @@ log-level = "debug"
 pnduuid = "bf8160d4-4659-4a1b-98fd-f409a04111ec"
 socket = ":55055"
 databaseConnection = "mongodb://root:example@clab-gosdn_csbi_arista_base-mongodb:27017"
+filesystemPathToStores = "stores"
 
diff --git a/controller/configs/development-gosdn.toml.example b/controller/configs/development-gosdn.toml.example
index 60f125602db6e8426f950aaf4daa0c006b2d14c7..6ae6a6a9450b2c2637cbec9366b0b8e8bcdfa9d1 100644
--- a/controller/configs/development-gosdn.toml.example
+++ b/controller/configs/development-gosdn.toml.example
@@ -10,4 +10,5 @@ log-level = "debug"
 pnduuid = "bf8160d4-4659-4a1b-98fd-f409a04111ec"
 socket = ":55055"
 databaseConnection = "mongodb://root:example@localhost:27017"
+filesystemPathToStores = "stores"
 
diff --git a/controller/interfaces/device/device.go b/controller/interfaces/device/device.go
index 73ccea34de71b163b5f35f55d47f6990c76176d1..497e7f9aea80e2a763a5ed8a9915ea15aefe03c1 100644
--- a/controller/interfaces/device/device.go
+++ b/controller/interfaces/device/device.go
@@ -32,8 +32,8 @@ type Details struct {
 // LoadedDevice represents a Orchestrated Networking Device that was loaeded
 // by using the Load() method of the DeviceStore.
 type LoadedDevice struct {
-	// DeviceID represents the UUID of the LoadedDevice.
-	DeviceID string `json:"id" bson:"_id"`
+	// ID represents the UUID of the LoadedDevice.
+	ID string `json:"id" bson:"_id"`
 	// Name represents the name of the LoadedDevice.
 	Name string `json:"name,omitempty"`
 	// TransportType represent the type of the transport in use of the LoadedDevice.
diff --git a/controller/northbound/server/pnd_test.go b/controller/northbound/server/pnd_test.go
index b7fb59e5bbf66829747c7d804f1e55468a2fdb52..797b5d52b3626cfe29d23c5241ebb70d5b7cd7ce 100644
--- a/controller/northbound/server/pnd_test.go
+++ b/controller/northbound/server/pnd_test.go
@@ -115,7 +115,7 @@ func TestMain(m *testing.M) {
 	mockPnd.On("ChangeOND", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(uuid.Nil, nil)
 	mockPnd.On("Request", mock.Anything, mock.Anything).Return(nil, nil)
 
-	pndc = nucleus.NewPndStore()
+	pndc = nucleus.NewMemoryPndStore()
 	if err := pndc.Add(mockPnd); err != nil {
 		log.Fatal(err)
 	}
diff --git a/controller/nucleus/device.go b/controller/nucleus/device.go
index fa25f32bbe2331f3d1dd4287528ead0a6248e647..db75615eb67619af21b6d927f9ad88af8c08e701 100644
--- a/controller/nucleus/device.go
+++ b/controller/nucleus/device.go
@@ -229,7 +229,7 @@ func (d *CommonDevice) MarshalJSON() ([]byte, error) {
 	}
 
 	return json.Marshal(&struct {
-		DeviceID            uuid.UUID `json:"id,omitempty"`
+		ID                  uuid.UUID `json:"id,omitempty"`
 		Name                string    `json:"name,omitempty"`
 		TransportType       string    `json:"transport_type,omitempty"`
 		TransportAddress    string    `json:"transport_address,omitempty"`
@@ -239,7 +239,7 @@ func (d *CommonDevice) MarshalJSON() ([]byte, error) {
 		SBI                 uuid.UUID `json:"sbi,omitempty"`
 		Model               string    `bson:"model,omitempty"`
 	}{
-		DeviceID:            d.ID(),
+		ID:                  d.ID(),
 		Name:                d.Name(),
 		TransportType:       transportType,
 		TransportAddress:    transportAddress,
@@ -282,7 +282,7 @@ func (d *CommonDevice) MarshalBSON() ([]byte, error) {
 	}
 
 	return bson.Marshal(&struct {
-		DeviceID            string   `bson:"_id,omitempty"`
+		ID                  string   `bson:"_id,omitempty"`
 		Name                string   `bson:"name,omitempty"`
 		TransportType       string   `bson:"transport_type,omitempty"`
 		TransportAddress    string   `bson:"transport_address,omitempty"`
@@ -292,7 +292,7 @@ func (d *CommonDevice) MarshalBSON() ([]byte, error) {
 		SBI                 string   `bson:"sbi,omitempty"`
 		Model               string   `bson:"model,omitempty"`
 	}{
-		DeviceID:            d.ID().String(),
+		ID:                  d.ID().String(),
 		Name:                d.Name(),
 		TransportType:       transportType,
 		TransportAddress:    transportAddress,
diff --git a/controller/nucleus/deviceFilesystemStore.go b/controller/nucleus/deviceFilesystemStore.go
new file mode 100644
index 0000000000000000000000000000000000000000..47d90d55ada59e9f5b7b568fb93efdc3495d7382
--- /dev/null
+++ b/controller/nucleus/deviceFilesystemStore.go
@@ -0,0 +1,174 @@
+package nucleus
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"sync"
+
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/device"
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
+	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
+	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/filesystem"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+	"github.com/google/uuid"
+)
+
+// FilesystemDeviceStore is the filesystem implementation of the device store
+type FilesystemDeviceStore struct {
+	sbiStore         southbound.Store
+	pndUUID          uuid.UUID
+	fileMutex        sync.Mutex
+	pathToDeviceFile string
+}
+
+// NewFilesystemDeviceStore returns a filesystem implementation for a pnd store.
+func NewFilesystemDeviceStore(pndUUID uuid.UUID) device.Store {
+	deviceFilenameForUUID := store.GetStoreFilenameForUUID(pndUUID, filesystem.DeviceFilenameSuffix)
+
+	store.EnsureFilesystemStorePathExists(deviceFilenameForUUID)
+	return &FilesystemDeviceStore{
+		pathToDeviceFile: store.GetCompletePathToFileStore(deviceFilenameForUUID),
+		fileMutex:        sync.Mutex{},
+		pndUUID:          pndUUID,
+	}
+}
+
+func (s *FilesystemDeviceStore) readAllDevicesFromFile() ([]device.LoadedDevice, error) {
+	var loadedDevices []device.LoadedDevice
+
+	content, err := ioutil.ReadFile(s.pathToDeviceFile)
+	if err != nil {
+		return nil, err
+	}
+
+	err = json.Unmarshal(content, &loadedDevices)
+	if err != nil {
+		return nil, err
+	}
+
+	return loadedDevices, nil
+}
+
+func (s *FilesystemDeviceStore) writeAllDevicesToFile(devices []device.LoadedDevice) error {
+	serializedData, err := json.Marshal(devices)
+	if err != nil {
+		return err
+	}
+
+	err = ioutil.WriteFile(s.pathToDeviceFile, serializedData, 0600)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Get takes a Device's UUID or name and returns the Device.
+func (s *FilesystemDeviceStore) Get(query store.Query) (device.LoadedDevice, error) {
+	s.fileMutex.Lock()
+	defer s.fileMutex.Unlock()
+
+	var device device.LoadedDevice
+
+	devices, err := s.readAllDevicesFromFile()
+	if err != nil {
+		return device, err
+	}
+
+	for _, device := range devices {
+		if device.ID == query.ID.String() {
+			return device, nil
+		}
+	}
+
+	return device, &errors.ErrNotFound{ID: query.ID}
+}
+
+// GetAll returns all stored devices.
+func (s *FilesystemDeviceStore) GetAll() ([]device.LoadedDevice, error) {
+	s.fileMutex.Lock()
+	defer s.fileMutex.Unlock()
+
+	devices, err := s.readAllDevicesFromFile()
+
+	return devices, err
+}
+
+// Add adds a device to the device store.
+func (s *FilesystemDeviceStore) Add(deviceToAdd device.Device) error {
+	s.fileMutex.Lock()
+	defer s.fileMutex.Unlock()
+
+	devices, err := s.readAllDevicesFromFile()
+	if err != nil {
+		return err
+	}
+
+	var loadedDevice device.LoadedDevice
+	loadedDevice, err = store.TransformObjectToLoadedObject[device.Device, device.LoadedDevice](deviceToAdd)
+	if err != nil {
+		return err
+	}
+
+	devices = append(devices, loadedDevice)
+
+	err = s.writeAllDevicesToFile(devices)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Update updates a existing device.
+func (s *FilesystemDeviceStore) Update(deviceToUpdate device.Device) error {
+	s.fileMutex.Lock()
+	defer s.fileMutex.Unlock()
+
+	var loadedDevice device.LoadedDevice
+
+	devices, err := s.readAllDevicesFromFile()
+	if err != nil {
+		return err
+	}
+
+	for i, device := range devices {
+		if device.ID == deviceToUpdate.ID().String() {
+			devices[i] = loadedDevice
+			err = s.writeAllDevicesToFile(devices)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	return &errors.ErrNotFound{ID: deviceToUpdate.ID().String()}
+}
+
+// Delete deletes a device from the device store.
+func (s *FilesystemDeviceStore) Delete(deviceToDelete device.Device) error {
+	s.fileMutex.Lock()
+	defer s.fileMutex.Unlock()
+
+	devices, err := s.readAllDevicesFromFile()
+	if err != nil {
+		return err
+	}
+
+	for i, device := range devices {
+		if device.ID == deviceToDelete.ID().String() {
+			//remove item from slice
+			devices[i] = devices[len(devices)-1]
+			devices = devices[:len(devices)-1]
+
+			err = s.writeAllDevicesToFile(devices)
+			if err != nil {
+				return err
+			}
+
+			return nil
+		}
+	}
+
+	return &errors.ErrNotFound{ID: deviceToDelete.ID}
+}
diff --git a/controller/nucleus/deviceFilesystemStore_test.go b/controller/nucleus/deviceFilesystemStore_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..6534627b1d47b1460b1e9efa7bc53656f5058034
--- /dev/null
+++ b/controller/nucleus/deviceFilesystemStore_test.go
@@ -0,0 +1,227 @@
+package nucleus
+
+import (
+	"log"
+	"os"
+	"path/filepath"
+	"testing"
+
+	spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
+	tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/device"
+	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/filesystem"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+	"github.com/google/uuid"
+)
+
+func ensureDeviceFilesForTestAreRemoved() {
+	store.EnsureFilesystemStorePathExists(filesystem.DeviceFilenameSuffix)
+	wildcartFilename := "*-" + filesystem.DeviceFilenameSuffix
+	path := store.GetCompletePathToFileStore(wildcartFilename)
+
+	files, err := filepath.Glob(path)
+
+	if err != nil {
+		log.Println(err)
+	}
+	for _, f := range files {
+		if err := os.Remove(f); err != nil {
+			log.Println(err)
+		}
+	}
+}
+
+func returnBasicTransportOption() tpb.TransportOption {
+	return tpb.TransportOption{
+		Address:  "test:///",
+		Username: "test",
+		Password: "test",
+		TransportOption: &tpb.TransportOption_GnmiTransportOption{
+			GnmiTransportOption: &tpb.GnmiTransportOption{
+				Compression:     "",
+				GrpcDialOptions: nil,
+				Token:           "",
+				Encoding:        0,
+			},
+		},
+	}
+}
+
+func TestAddDevice(t *testing.T) {
+	ensureDeviceFilesForTestAreRemoved()
+	defer ensureDeviceFilesForTestAreRemoved()
+
+	pndID, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+	deviceID, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
+	sbiID1, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
+
+	sbi1, _ := NewSBI(spb.Type_TYPE_OPENCONFIG, sbiID1)
+
+	deviceStore := NewDeviceStore(pndID)
+	device, _ := NewDevice("testdevice", deviceID, nil, sbi1)
+
+	err := deviceStore.Add(device)
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+func TestGetAllDevices(t *testing.T) {
+	ensureDeviceFilesForTestAreRemoved()
+	defer ensureDeviceFilesForTestAreRemoved()
+
+	pndID, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+	deviceStore := NewDeviceStore(pndID)
+
+	sbiID, _ := uuid.Parse("ssssssss-ssss-ssss-ssss-ssssssssssss")
+	sbi, _ := NewSBI(spb.Type_TYPE_OPENCONFIG, sbiID)
+
+	deviceID1, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
+	deviceID2, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaab")
+
+	transportOptions := returnBasicTransportOption()
+
+	device1, err := NewDevice("testname", deviceID1, &transportOptions, sbi)
+	if err != nil {
+		t.Error(err)
+	}
+
+	device2, err := NewDevice("testname2", deviceID2, &transportOptions, sbi)
+	if err != nil {
+		t.Error(err)
+	}
+
+	inputDevices := [2]device.Device{device1, device2}
+
+	for _, device := range inputDevices {
+		err := deviceStore.Add(device)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	returnedDevices, err := deviceStore.GetAll()
+	if err != nil {
+		t.Error(err)
+	}
+
+	length := len(returnedDevices)
+	if length != 2 {
+		t.Errorf("GetAll() length of array = %v, want %v", length, 2)
+	}
+
+	for i, device := range returnedDevices {
+		if device.ID != inputDevices[i].ID().String() {
+			t.Errorf("GetAll() = %v, want %v", device.ID, inputDevices[i].ID().String())
+		}
+		if device.Name != inputDevices[i].Name() {
+			t.Errorf("GetAll() = %v, want %v", device.Name, inputDevices[i].Name())
+		}
+	}
+}
+
+func TestGetDevice(t *testing.T) {
+	ensureDeviceFilesForTestAreRemoved()
+	defer ensureDeviceFilesForTestAreRemoved()
+
+	pndID, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+	deviceStore := NewDeviceStore(pndID)
+
+	sbiID, _ := uuid.Parse("ssssssss-ssss-ssss-ssss-ssssssssssss")
+	sbi, _ := NewSBI(spb.Type_TYPE_OPENCONFIG, sbiID)
+
+	deviceID1, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
+	deviceID2, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaab")
+
+	trop := returnBasicTransportOption()
+
+	device1, err := NewDevice("testname", deviceID1, &trop, sbi)
+	if err != nil {
+		t.Error(err)
+	}
+
+	device2, err := NewDevice("testname2", deviceID2, &trop, sbi)
+	if err != nil {
+		t.Error(err)
+	}
+
+	inputDevices := [2]device.Device{device1, device2}
+
+	for _, device := range inputDevices {
+		err := deviceStore.Add(device)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	returnDevice, err := deviceStore.Get(store.Query{ID: deviceID2, Name: "testname2"})
+	if err != nil {
+		t.Error(err)
+	}
+
+	if returnDevice.ID != inputDevices[1].ID().String() {
+		t.Errorf("GetAll() = %v, want %v", returnDevice.ID, inputDevices[1].ID().String())
+	}
+	if returnDevice.Name != inputDevices[1].Name() {
+		t.Errorf("GetAll() = %v, want %v", returnDevice.Name, inputDevices[1].Name())
+	}
+}
+
+func TestDeleteDevice(t *testing.T) {
+	ensureDeviceFilesForTestAreRemoved()
+	defer ensureDeviceFilesForTestAreRemoved()
+
+	pndID, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+	deviceStore := NewDeviceStore(pndID)
+
+	sbiID, _ := uuid.Parse("ssssssss-ssss-ssss-ssss-ssssssssssss")
+	sbi, _ := NewSBI(spb.Type_TYPE_OPENCONFIG, sbiID)
+
+	deviceID1, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
+	deviceID2, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaab")
+
+	trop := returnBasicTransportOption()
+
+	device1, err := NewDevice("testname", deviceID1, &trop, sbi)
+	if err != nil {
+		t.Error(err)
+	}
+
+	device2, err := NewDevice("testname2", deviceID2, &trop, sbi)
+	if err != nil {
+		t.Error(err)
+	}
+
+	inputDevices := [2]device.Device{device1, device2}
+
+	for _, device := range inputDevices {
+		err := deviceStore.Add(device)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	err = deviceStore.Delete(device1)
+	if err != nil {
+		t.Error(err)
+	}
+
+	returnDevices, err := deviceStore.GetAll()
+	if err != nil {
+		t.Error(err)
+	}
+
+	length := len(returnDevices)
+	if length != 1 {
+		t.Errorf("GetAll() length of array = %v, want %v", length, 2)
+	}
+
+	for _, device := range returnDevices {
+		if device.ID != inputDevices[1].ID().String() {
+			t.Errorf("GetAll() = %v, want %v", device.ID, inputDevices[1].ID().String())
+		}
+		if device.Name != inputDevices[1].Name() {
+			t.Errorf("GetAll() = %v, want %v", device.Name, inputDevices[1].Name())
+		}
+	}
+}
diff --git a/controller/nucleus/deviceService.go b/controller/nucleus/deviceService.go
index 6679b974e63cbd4c9cc7360271da2152a2399830..30caff6dccec364d4f58b7fc98de7689f3c392cd 100644
--- a/controller/nucleus/deviceService.go
+++ b/controller/nucleus/deviceService.go
@@ -106,7 +106,7 @@ func (s *DeviceService) createDeviceFromStore(loadedDevice device.LoadedDevice)
 
 	d, err := NewDevice(
 		loadedDevice.Name,
-		uuid.MustParse(loadedDevice.DeviceID),
+		uuid.MustParse(loadedDevice.ID),
 		&tpb.TransportOption{
 			Address:  loadedDevice.TransportAddress,
 			Username: loadedDevice.TransportUsername,
diff --git a/controller/nucleus/deviceStore.go b/controller/nucleus/deviceStore.go
index 04fa24ba7b03bd53f19292c272d464bf2d3cf3cd..aa886eb11bbc5fdb3c3e26563de22385f01b704d 100644
--- a/controller/nucleus/deviceStore.go
+++ b/controller/nucleus/deviceStore.go
@@ -4,7 +4,6 @@ import (
 	"fmt"
 
 	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/device"
-	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
 	"code.fbi.h-da.de/danet/gosdn/controller/store"
 
 	"github.com/google/uuid"
@@ -15,31 +14,19 @@ const (
 	deviceStoreName = "device"
 )
 
-// DeviceStore is used to store Devices
-type DeviceStore struct {
-	storeName string
-	sbiStore  southbound.Store
-}
-
 // NewDeviceStore returns a DeviceStore
 func NewDeviceStore(pndUUID uuid.UUID) device.Store {
 	storeMode := store.GetStoreMode()
 	log.Debugf("StoreMode: %s", storeMode)
 
 	switch storeMode {
-	case store.Filesystem:
-		store := NewMemoryDeviceStore()
-
-		return store
 	case store.Database:
 		return &DatabaseDeviceStore{
 			storeName: fmt.Sprintf("device-store-%s.json", pndUUID.String()),
 		}
-	case store.Memory:
-		store := NewMemoryDeviceStore()
 
-		return store
 	default:
-		return nil
+		store := NewFilesystemDeviceStore(pndUUID)
+		return store
 	}
 }
diff --git a/controller/nucleus/filesystem/filesystem-settings.go b/controller/nucleus/filesystem/filesystem-settings.go
new file mode 100644
index 0000000000000000000000000000000000000000..8df6e31e7ea541fa4484c7c83c125bfe8925682d
--- /dev/null
+++ b/controller/nucleus/filesystem/filesystem-settings.go
@@ -0,0 +1,10 @@
+package filesystem
+
+const (
+	// PndFilename is the name of the file where the pnds are stored
+	PndFilename string = "pndStore.json"
+	// DeviceFilenameSuffix is the suffix of the file where the devices are stored
+	DeviceFilenameSuffix string = "deviceStore.json"
+	// SbiFilenameSuffix is the suffix of the file where the sbis are stored
+	SbiFilenameSuffix string = "sbiStore.json"
+)
diff --git a/controller/nucleus/memoryDeviceStore.go b/controller/nucleus/memoryDeviceStore.go
index 9a04d7a5c1c3fa06648e1eddefe7c2156ce35dcd..a7c775a88257ed6de027eb87a521c49ee417a8c8 100644
--- a/controller/nucleus/memoryDeviceStore.go
+++ b/controller/nucleus/memoryDeviceStore.go
@@ -35,13 +35,13 @@ func (t *MemoryDeviceStore) Add(item device.Device) error {
 		return err
 	}
 
-	_, ok := t.Store[device.DeviceID]
+	_, ok := t.Store[device.ID]
 	if ok {
 		return nil
 	}
 
-	t.Store[device.DeviceID] = device
-	t.nameLookupTable[item.Name()] = device.DeviceID
+	t.Store[device.ID] = device
+	t.nameLookupTable[item.Name()] = device.ID
 
 	return nil
 }
diff --git a/controller/nucleus/memoryPndStore.go b/controller/nucleus/memoryPndStore.go
index 92236742000bbb29594377f62b4197c22087f866..57cb3289d3a327b333491fe8005e980b9c4daa03 100644
--- a/controller/nucleus/memoryPndStore.go
+++ b/controller/nucleus/memoryPndStore.go
@@ -15,8 +15,8 @@ type MemoryPndStore struct {
 }
 
 // NewMemoryPndStore returns a in-memory implementation for a pnd store.
-func NewMemoryPndStore() MemoryPndStore {
-	return MemoryPndStore{
+func NewMemoryPndStore() networkdomain.PndStore {
+	return &MemoryPndStore{
 		Store:           make(map[uuid.UUID]networkdomain.NetworkDomain),
 		pendingChannels: make(map[uuid.UUID]chan device.Details),
 	}
diff --git a/controller/nucleus/pndFilesystemStore.go b/controller/nucleus/pndFilesystemStore.go
new file mode 100644
index 0000000000000000000000000000000000000000..c9c15c055b3f7615c438b8bbd00a7e0126d2ab4b
--- /dev/null
+++ b/controller/nucleus/pndFilesystemStore.go
@@ -0,0 +1,209 @@
+package nucleus
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"sync"
+
+	cpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/csbi"
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/device"
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain"
+	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
+	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/filesystem"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+	"github.com/google/uuid"
+	log "github.com/sirupsen/logrus"
+	"github.com/spf13/viper"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials/insecure"
+)
+
+// FilesystemPndStore provides a filesystem implementation for a pnd store.
+type FilesystemPndStore struct {
+	pendingChannels map[uuid.UUID]chan device.Details
+	csbiClient      cpb.CsbiServiceClient
+	pathToPndFile   string
+	fileMutex       sync.Mutex
+}
+
+// NewFilesystemPndStore returns a filesystem implementation for a pnd store.
+func NewFilesystemPndStore() FilesystemPndStore {
+	store.EnsureFilesystemStorePathExists(filesystem.PndFilename)
+	return FilesystemPndStore{
+		pendingChannels: make(map[uuid.UUID]chan device.Details),
+		pathToPndFile:   store.GetCompletePathToFileStore(filesystem.PndFilename),
+		fileMutex:       sync.Mutex{},
+	}
+}
+
+func (t *FilesystemPndStore) readAllPndsFromFile() ([]networkdomain.NetworkDomain, error) {
+	var loadedPnds []LoadedPnd
+
+	content, err := ioutil.ReadFile(t.pathToPndFile)
+	if err != nil {
+		return nil, err
+	}
+
+	err = json.Unmarshal(content, &loadedPnds)
+	if err != nil {
+		return nil, err
+	}
+
+	pnds := make([]networkdomain.NetworkDomain, len(loadedPnds))
+
+	csbiClient, err := t.getCsbiClient()
+	if err != nil {
+		return nil, err
+	}
+
+	for i, loadedPND := range loadedPnds {
+		newPnd, err := NewPND(
+			loadedPND.Name,
+			loadedPND.Description,
+			uuid.MustParse(loadedPND.ID),
+			csbiClient,
+			t.callback,
+		)
+		if err != nil {
+			return nil, err
+		}
+
+		pnds[i] = newPnd
+	}
+	return pnds, nil
+}
+
+func (t *FilesystemPndStore) writeAllPndsToFile(pnds []networkdomain.NetworkDomain) error {
+	serializedData, err := json.Marshal(pnds)
+	if err != nil {
+		return err
+	}
+
+	err = ioutil.WriteFile(t.pathToPndFile, serializedData, 0600)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Add a pnd to the store.
+func (t *FilesystemPndStore) Add(item networkdomain.NetworkDomain) error {
+	t.fileMutex.Lock()
+	defer t.fileMutex.Unlock()
+
+	pnds, err := t.readAllPndsFromFile()
+	if err != nil {
+		return err
+	}
+
+	pnds = append(pnds, item)
+
+	err = t.writeAllPndsToFile(pnds)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Delete deletes a pnd from the store.
+func (t *FilesystemPndStore) Delete(item networkdomain.NetworkDomain) error {
+	t.fileMutex.Lock()
+	defer t.fileMutex.Unlock()
+
+	pnds, err := t.readAllPndsFromFile()
+	if err != nil {
+		return err
+	}
+
+	for i, pnd := range pnds {
+		if pnd.ID() == item.ID() {
+			//remove item from slice
+			pnds[i] = pnds[len(pnds)-1]
+			pnds = pnds[:len(pnds)-1]
+
+			err = t.writeAllPndsToFile(pnds)
+			if err != nil {
+				return err
+			}
+
+			return nil
+		}
+	}
+
+	return &errors.ErrNotFound{ID: item.ID}
+}
+
+// Get provides a the query interface to find a stored pnd.
+func (t *FilesystemPndStore) Get(query store.Query) (networkdomain.NetworkDomain, error) {
+	t.fileMutex.Lock()
+	defer t.fileMutex.Unlock()
+
+	pnds, err := t.readAllPndsFromFile()
+	if err != nil {
+		return nil, err
+	}
+
+	for _, pnd := range pnds {
+		if pnd.ID() == query.ID {
+			return pnd, nil
+		}
+	}
+
+	return nil, &errors.ErrNotFound{ID: query.ID}
+}
+
+// GetAll returns all pnds currently on the store.
+func (t *FilesystemPndStore) GetAll() ([]networkdomain.NetworkDomain, error) {
+	t.fileMutex.Lock()
+	defer t.fileMutex.Unlock()
+
+	pnds, err := t.readAllPndsFromFile()
+
+	return pnds, err
+}
+
+// PendingChannels holds channels used communicate with pending
+// cSBI deployments
+func (t *FilesystemPndStore) PendingChannels(id uuid.UUID, parseErrors ...error) (chan device.Details, error) {
+	ch, ok := t.pendingChannels[id]
+	if !ok {
+		return nil, &errors.ErrNotFound{ID: id}
+	}
+	return ch, nil
+}
+
+// AddPendingChannel adds a pending channel to the map
+func (t *FilesystemPndStore) AddPendingChannel(id uuid.UUID, ch chan device.Details) {
+	t.pendingChannels[id] = ch
+}
+
+// RemovePendingChannel removes a pending channel from the map
+func (t *FilesystemPndStore) RemovePendingChannel(id uuid.UUID) {
+	delete(t.pendingChannels, id)
+}
+
+func (t *FilesystemPndStore) callback(id uuid.UUID, ch chan device.Details) {
+	if ch != nil {
+		t.AddPendingChannel(id, ch)
+		log.Infof("pending channel %v added", id)
+	} else {
+		t.RemovePendingChannel(id)
+		log.Infof("pending channel %v removed", id)
+	}
+}
+
+func (t *FilesystemPndStore) getCsbiClient() (cpb.CsbiServiceClient, error) {
+	if t.csbiClient == nil {
+		orchestrator := viper.GetString("csbi-orchestrator")
+		conn, err := grpc.Dial(orchestrator, grpc.WithTransportCredentials(insecure.NewCredentials()))
+		if err != nil {
+			return nil, err
+		}
+
+		t.csbiClient = cpb.NewCsbiServiceClient(conn)
+	}
+
+	return t.csbiClient, nil
+}
diff --git a/controller/nucleus/pndFilesystemStore_test.go b/controller/nucleus/pndFilesystemStore_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..3480c6a5392c90c7f0ac59e14906c63bcea722fb
--- /dev/null
+++ b/controller/nucleus/pndFilesystemStore_test.go
@@ -0,0 +1,158 @@
+package nucleus
+
+import (
+	"log"
+	"os"
+	"testing"
+
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain"
+	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/filesystem"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+	"github.com/google/uuid"
+)
+
+func ensurePndFileForTestIsRemoved() {
+	store.EnsureFilesystemStorePathExists(filesystem.PndFilename)
+	path := store.GetCompletePathToFileStore(filesystem.PndFilename)
+
+	err := os.Remove(path)
+	if err != nil {
+		log.Println(err)
+	}
+}
+
+func TestAddPnd(t *testing.T) {
+	ensurePndFileForTestIsRemoved()
+	defer ensurePndFileForTestIsRemoved()
+
+	pndStore := NewPndStore()
+
+	pndID, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+	pnd, _ := NewPND("testpnd", "test", pndID, nil, nil)
+
+	err := pndStore.Add(pnd)
+
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+func TestGetAllPnds(t *testing.T) {
+	ensurePndFileForTestIsRemoved()
+	defer ensurePndFileForTestIsRemoved()
+
+	pndStore := NewPndStore()
+	pndID1, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+	pndID2, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bab")
+	pnd1, _ := NewPND("testpnd", "test", pndID1, nil, nil)
+	pnd2, _ := NewPND("testpnd2", "test", pndID2, nil, nil)
+
+	inputPnds := [2]networkdomain.NetworkDomain{pnd1, pnd2}
+
+	for _, pnd := range inputPnds {
+		err := pndStore.Add(pnd)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	returnPnds, err := pndStore.GetAll()
+	if err != nil {
+		t.Error(err)
+	}
+
+	for i, pnd := range returnPnds {
+		if pnd.GetName() != inputPnds[i].GetName() {
+			t.Errorf("GetAll() = %v, want %v", pnd.GetName(), inputPnds[i].GetName())
+		}
+		if pnd.GetDescription() != inputPnds[i].GetDescription() {
+			t.Errorf("GetAll() = %v, want %v", pnd.GetDescription(), inputPnds[i].GetDescription())
+		}
+		if pnd.ID() != inputPnds[i].ID() {
+			t.Errorf("GetAll() = %v, want %v", pnd.ID(), inputPnds[i].ID())
+		}
+	}
+}
+
+func TestGetPnd(t *testing.T) {
+	ensurePndFileForTestIsRemoved()
+	defer ensurePndFileForTestIsRemoved()
+
+	pndStore := NewPndStore()
+	pndID1, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+	pndID2, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bab")
+	pnd1, _ := NewPND("testpnd", "test", pndID1, nil, nil)
+	pnd2, _ := NewPND("testpnd2", "test", pndID2, nil, nil)
+
+	inputPnds := [2]networkdomain.NetworkDomain{pnd1, pnd2}
+
+	for _, pnd := range inputPnds {
+		err := pndStore.Add(pnd)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	returnPnd, err := pndStore.Get(store.Query{ID: pndID2, Name: ""})
+	if err != nil {
+		t.Error(err)
+	}
+
+	if returnPnd.GetName() != pnd2.GetName() {
+		t.Errorf("GetAll() = %v, want %v", pnd2.GetName(), returnPnd.GetName())
+	}
+	if returnPnd.GetDescription() != pnd2.GetDescription() {
+		t.Errorf("GetAll() = %v, want %v", pnd2.GetDescription(), returnPnd.GetDescription())
+	}
+	if returnPnd.ID() != pnd2.ID() {
+		t.Errorf("GetAll() = %v, want %v", pnd2.ID(), returnPnd.ID())
+	}
+}
+
+func TestDeletePnd(t *testing.T) {
+	ensurePndFileForTestIsRemoved()
+	defer ensurePndFileForTestIsRemoved()
+
+	pndStore := NewPndStore()
+	pndID1, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+	pndID2, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bab")
+	pnd1, _ := NewPND("testpnd", "test", pndID1, nil, nil)
+	pnd2, _ := NewPND("testpnd2", "test", pndID2, nil, nil)
+
+	inputPnds := [2]networkdomain.NetworkDomain{pnd1, pnd2}
+
+	for _, pnd := range inputPnds {
+		err := pndStore.Add(pnd)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	err := pndStore.Delete(pnd1)
+	if err != nil {
+		t.Error(err)
+	}
+
+	returnPnds, err := pndStore.GetAll()
+	if err != nil {
+		t.Error(err)
+	}
+
+	length := len(returnPnds)
+	if length != 1 {
+		t.Errorf("GetAll() length of array = %v, want %v", length, 1)
+	}
+
+	//only check first element in this case
+	for i, pnd := range returnPnds[1:] {
+		if pnd.GetName() != inputPnds[i].GetName() {
+			t.Errorf("GetAll() = %v, want %v", pnd.GetName(), inputPnds[i].GetName())
+		}
+		if pnd.GetDescription() != inputPnds[i].GetDescription() {
+			t.Errorf("GetAll() = %v, want %v", pnd.GetDescription(), inputPnds[i].GetDescription())
+		}
+		if pnd.ID() != inputPnds[i].ID() {
+			t.Errorf("GetAll() = %v, want %v", pnd.ID(), inputPnds[i].ID())
+		}
+	}
+}
diff --git a/controller/nucleus/pndStore.go b/controller/nucleus/pndStore.go
index 7b621db0217953aa1688a5ad479bc6ec557a6dcf..876e03742f71b2503aa6fb60bb629df00ee7d5a4 100644
--- a/controller/nucleus/pndStore.go
+++ b/controller/nucleus/pndStore.go
@@ -32,19 +32,13 @@ func NewPndStore() networkdomain.PndStore {
 	log.Debugf("StoreMode: %s", storeMode)
 
 	switch storeMode {
-	case store.Filesystem:
-		store := NewMemoryPndStore()
-
-		return &store
 	case store.Database:
 		return &DatabasePndStore{
 			pendingChannels: make(map[uuid.UUID]chan device.Details),
 			pndStoreName:    "pnd-store.json"}
-	case store.Memory:
-		store := NewMemoryPndStore()
 
-		return &store
 	default:
-		return nil
+		store := NewFilesystemPndStore()
+		return &store
 	}
 }
diff --git a/controller/nucleus/principalNetworkDomain_test.go b/controller/nucleus/principalNetworkDomain_test.go
index fdd4644c94cc63ea2a7847d138162a20a864365f..26212e9e0b88d804328fd4203ee340dd884b3a97 100644
--- a/controller/nucleus/principalNetworkDomain_test.go
+++ b/controller/nucleus/principalNetworkDomain_test.go
@@ -365,8 +365,8 @@ func Test_pndImplementation_RemoveSbi(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			sbiStore := NewSbiStore(defaultPndID)
-			deviceStore := NewDeviceStore(defaultPndID)
+			sbiStore := NewMemorySbiStore()
+			deviceStore := NewMemoryDeviceStore()
 			sbiService := NewSbiService(sbiStore)
 			deviceService := NewDeviceService(deviceStore, sbiService)
 
@@ -430,8 +430,8 @@ func Test_pndImplementation_RemoveSbiWithAssociatedDevices(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			sbiStore := NewSbiStore(defaultPndID)
-			deviceStore := NewDeviceStore(defaultPndID)
+			sbiStore := NewMemorySbiStore()
+			deviceStore := NewMemoryDeviceStore()
 			sbiService := NewSbiService(sbiStore)
 			deviceService := NewDeviceService(deviceStore, sbiService)
 
diff --git a/controller/nucleus/sbiFilesystemStore.go b/controller/nucleus/sbiFilesystemStore.go
new file mode 100644
index 0000000000000000000000000000000000000000..9337d37e646eb0f3e59ca22f5f2f298bd8e16b02
--- /dev/null
+++ b/controller/nucleus/sbiFilesystemStore.go
@@ -0,0 +1,147 @@
+package nucleus
+
+import (
+	"encoding/json"
+	"io/ioutil"
+	"sync"
+
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
+	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
+	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/filesystem"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+
+	"github.com/google/uuid"
+)
+
+// FilesystemSbiStore is used to store SouthboundInterfaces
+type FilesystemSbiStore struct {
+	sbiStoreName  string
+	pndUUID       uuid.UUID
+	fileMutex     sync.Mutex
+	pathToSbiFile string
+}
+
+// NewFilesystemSbiStore returns a filesystem implementation for a pnd store.
+func NewFilesystemSbiStore(pndUUID uuid.UUID) southbound.Store {
+	sbiFilenameForUUID := store.GetStoreFilenameForUUID(pndUUID, filesystem.SbiFilenameSuffix)
+
+	store.EnsureFilesystemStorePathExists(sbiFilenameForUUID)
+	return &FilesystemSbiStore{
+		pathToSbiFile: store.GetCompletePathToFileStore(sbiFilenameForUUID),
+		fileMutex:     sync.Mutex{},
+		pndUUID:       pndUUID,
+	}
+}
+
+func (s *FilesystemSbiStore) readAllSbisFromFile() ([]southbound.LoadedSbi, error) {
+	var loadedSbis []southbound.LoadedSbi
+
+	content, err := ioutil.ReadFile(s.pathToSbiFile)
+	if err != nil {
+		return nil, err
+	}
+
+	err = json.Unmarshal(content, &loadedSbis)
+	if err != nil {
+		return nil, err
+	}
+	return loadedSbis, nil
+}
+
+func (s *FilesystemSbiStore) writeAllSbisToFile(sbis []southbound.LoadedSbi) error {
+	serializedData, err := json.Marshal(sbis)
+	if err != nil {
+		return err
+	}
+
+	err = ioutil.WriteFile(s.pathToSbiFile, serializedData, 0600)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// Add adds a SBI.
+func (s *FilesystemSbiStore) Add(sbiToAdd southbound.SouthboundInterface) error {
+	s.fileMutex.Lock()
+	defer s.fileMutex.Unlock()
+
+	sbis, err := s.readAllSbisFromFile()
+	if err != nil {
+		return err
+	}
+
+	var loadedSbi southbound.LoadedSbi
+	loadedSbi, err = store.TransformObjectToLoadedObject[southbound.SouthboundInterface, southbound.LoadedSbi](sbiToAdd)
+	if err != nil {
+		return err
+	}
+
+	sbis = append(sbis, loadedSbi)
+
+	err = s.writeAllSbisToFile(sbis)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Delete deletes an SBI.
+func (s *FilesystemSbiStore) Delete(sbiToDelete southbound.SouthboundInterface) error {
+	s.fileMutex.Lock()
+	defer s.fileMutex.Unlock()
+
+	sbis, err := s.readAllSbisFromFile()
+	if err != nil {
+		return err
+	}
+
+	for i, device := range sbis {
+		if device.ID == sbiToDelete.ID().String() {
+			//remove item from slice
+			sbis[i] = sbis[len(sbis)-1]
+			sbis = sbis[:len(sbis)-1]
+
+			err = s.writeAllSbisToFile(sbis)
+			if err != nil {
+				return err
+			}
+
+			return nil
+		}
+	}
+	return &errors.ErrNotFound{ID: sbiToDelete.ID}
+}
+
+// Get takes a SouthboundInterface's UUID or name and returns the SouthboundInterface. If the requested
+// SouthboundInterface does not exist an error is returned.
+func (s *FilesystemSbiStore) Get(query store.Query) (southbound.LoadedSbi, error) {
+	s.fileMutex.Lock()
+	defer s.fileMutex.Unlock()
+
+	var sbi southbound.LoadedSbi
+
+	sbis, err := s.readAllSbisFromFile()
+	if err != nil {
+		return sbi, err
+	}
+
+	for _, device := range sbis {
+		if device.ID == query.ID.String() {
+			return device, nil
+		}
+	}
+
+	return sbi, &errors.ErrNotFound{ID: query.ID}
+}
+
+// GetAll returns all SBIs
+func (s *FilesystemSbiStore) GetAll() ([]southbound.LoadedSbi, error) {
+	s.fileMutex.Lock()
+	defer s.fileMutex.Unlock()
+
+	sbis, err := s.readAllSbisFromFile()
+
+	return sbis, err
+}
diff --git a/controller/nucleus/sbiFilesystemStore_test.go b/controller/nucleus/sbiFilesystemStore_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..38ea67d4723ee950e00ba74c05d5b08b286549ae
--- /dev/null
+++ b/controller/nucleus/sbiFilesystemStore_test.go
@@ -0,0 +1,162 @@
+package nucleus
+
+import (
+	"log"
+	"os"
+	"path/filepath"
+	"testing"
+
+	spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
+	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/filesystem"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+	"github.com/google/uuid"
+)
+
+func ensureSbiFilesForTestAreRemoved() {
+	store.EnsureFilesystemStorePathExists(filesystem.SbiFilenameSuffix)
+	wildcartFilename := "*-" + filesystem.SbiFilenameSuffix
+	path := store.GetCompletePathToFileStore(wildcartFilename)
+
+	files, err := filepath.Glob(path)
+
+	if err != nil {
+		log.Println(err)
+	}
+	for _, f := range files {
+		if err := os.Remove(f); err != nil {
+			log.Println(err)
+		}
+	}
+}
+
+func TestAddSbi(t *testing.T) {
+	ensureSbiFilesForTestAreRemoved()
+	defer ensureSbiFilesForTestAreRemoved()
+
+	pndID, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+	sbiStore := NewSbiStore(pndID)
+
+	sbiID, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
+
+	sbi, _ := NewSBI(spb.Type_TYPE_OPENCONFIG, sbiID)
+
+	err := sbiStore.Add(sbi)
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+func TestGetAllSbis(t *testing.T) {
+	ensureSbiFilesForTestAreRemoved()
+	defer ensureSbiFilesForTestAreRemoved()
+
+	pndID, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+	sbiStore := NewSbiStore(pndID)
+
+	sbiID1, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
+	sbiID2, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaab")
+
+	sbi1, _ := NewSBI(spb.Type_TYPE_OPENCONFIG, sbiID1)
+	sbi2, _ := NewSBI(spb.Type_TYPE_OPENCONFIG, sbiID2)
+
+	inputSbis := [2]southbound.SouthboundInterface{sbi1, sbi2}
+
+	for _, sbi := range inputSbis {
+		err := sbiStore.Add(sbi)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	returnSbis, err := sbiStore.GetAll()
+	if err != nil {
+		t.Error(err)
+	}
+
+	length := len(returnSbis)
+	if length != 2 {
+		t.Errorf("GetAll() length of array = %v, want %v", length, 2)
+	}
+
+	for i, sbi := range returnSbis {
+		if sbi.ID != inputSbis[i].ID().String() {
+			t.Errorf("GetAll() = %v, want %v", sbi.ID, inputSbis[i].ID().String())
+		}
+	}
+}
+
+func TestGetSbi(t *testing.T) {
+	ensureSbiFilesForTestAreRemoved()
+	defer ensureSbiFilesForTestAreRemoved()
+
+	pndID, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+
+	sbiStore := NewSbiStore(pndID)
+
+	sbiID1, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
+	sbiID2, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaab")
+
+	sbi1, _ := NewSBI(spb.Type_TYPE_OPENCONFIG, sbiID1)
+	sbi2, _ := NewSBI(spb.Type_TYPE_OPENCONFIG, sbiID2)
+
+	inputSbis := [2]southbound.SouthboundInterface{sbi1, sbi2}
+
+	for _, sbi := range inputSbis {
+		err := sbiStore.Add(sbi)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	returnSbi, err := sbiStore.Get(store.Query{ID: sbiID2, Name: ""})
+	if err != nil {
+		t.Error(err)
+	}
+
+	if returnSbi.ID != sbi2.ID().String() {
+		t.Errorf("Get() = %v, want %v", returnSbi.ID, sbi2.ID().String())
+	}
+}
+
+func TestDeleteAllSbis(t *testing.T) {
+	ensureSbiFilesForTestAreRemoved()
+	defer ensureSbiFilesForTestAreRemoved()
+
+	pndID, _ := uuid.Parse("b4016412-eec5-45a1-aa29-f59915357bad")
+	sbiStore := NewSbiStore(pndID)
+
+	sbiID1, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")
+	sbiID2, _ := uuid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaab")
+
+	sbi1, _ := NewSBI(spb.Type_TYPE_OPENCONFIG, sbiID1)
+	sbi2, _ := NewSBI(spb.Type_TYPE_OPENCONFIG, sbiID2)
+
+	inputSbis := [2]southbound.SouthboundInterface{sbi1, sbi2}
+
+	for _, sbi := range inputSbis {
+		err := sbiStore.Add(sbi)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	err := sbiStore.Delete(sbi1)
+	if err != nil {
+		t.Error(err)
+	}
+
+	returnSbis, err := sbiStore.GetAll()
+	if err != nil {
+		t.Error(err)
+	}
+
+	length := len(returnSbis)
+	if length != 1 {
+		t.Errorf("GetAll() length of array = %v, want %v", length, 2)
+	}
+
+	if returnSbis[0].ID != inputSbis[1].ID().String() {
+		t.Errorf("GetAll() = %v, want %v", returnSbis[0].ID, inputSbis[1].ID().String())
+	}
+}
diff --git a/controller/nucleus/sbiStore.go b/controller/nucleus/sbiStore.go
index 7038980cfb26fec86fa0c4d348544f3eb25df509..fa992e4c1be4b1e8fbe993db59b8545658db2f7b 100644
--- a/controller/nucleus/sbiStore.go
+++ b/controller/nucleus/sbiStore.go
@@ -23,19 +23,13 @@ func NewSbiStore(pndUUID uuid.UUID) southbound.Store {
 	storeMode := store.GetStoreMode()
 
 	switch storeMode {
-	case store.Filesystem:
-		store := NewMemorySbiStore()
-
-		return store
 	case store.Database:
 		return &DatabaseSbiStore{
 			sbiStoreName: fmt.Sprintf("sbi-store-%s.json", pndUUID.String()),
 		}
-	case store.Memory:
-		store := NewMemorySbiStore()
 
-		return store
 	default:
-		return nil
+		store := NewFilesystemSbiStore(pndUUID)
+		return store
 	}
 }
diff --git a/controller/store/storageMode.go b/controller/store/storageMode.go
index 513fb96935f847565719a0a9cea792e1b0fb8dfc..bd295dc345afdbfcf056fe36af5de060300da800 100644
--- a/controller/store/storageMode.go
+++ b/controller/store/storageMode.go
@@ -20,13 +20,11 @@ func GetStoreMode() StorageMode {
 		return Database
 	}
 
-	return Memory
+	return Filesystem
 }
 
 func (s StorageMode) String() string {
 	switch s {
-	case Memory:
-		return "Memory"
 	case Filesystem:
 		return "Filesystem"
 	case Database:
diff --git a/controller/store/utils.go b/controller/store/utils.go
index b329ffb65376c716bc90f45ccc669b7499397301..769889c7c27d59d201ffed3eb4a0aaf796e989d8 100644
--- a/controller/store/utils.go
+++ b/controller/store/utils.go
@@ -1,6 +1,11 @@
 package store
 
 import (
+	"encoding/json"
+	"os"
+	"path/filepath"
+
+	"code.fbi.h-da.de/danet/gosdn/controller/config"
 	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
 	"github.com/google/uuid"
 	log "github.com/sirupsen/logrus"
@@ -21,3 +26,70 @@ func FromString(id string) (uuid.UUID, error) {
 
 	return idAsUUID, nil
 }
+
+//EnsureFilesystemStorePathExists ensures that the filesystem store path exists
+func EnsureFilesystemStorePathExists(storeFileName string) error {
+	completeStorePath := filepath.Join(config.FilesystemPathToStores, storeFileName)
+	if _, err := os.Stat(completeStorePath); os.IsNotExist(err) {
+		err := ensureFileSystemStoreExists(completeStorePath)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func ensureFileSystemStoreExists(pathToStore string) error {
+	err := ensureDirExists(pathToStore)
+	if err != nil {
+		return err
+	}
+
+	emptyArray := []byte("[]")
+	err = os.WriteFile(pathToStore, emptyArray, 0600)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func ensureDirExists(fileName string) error {
+	dirName := filepath.Dir(fileName)
+	if _, serr := os.Stat(dirName); serr != nil {
+		merr := os.MkdirAll(dirName, os.ModePerm)
+		if merr != nil {
+			return merr
+		}
+	}
+
+	return nil
+}
+
+//GetCompletePathToFileStore gets the complete path to a file store
+func GetCompletePathToFileStore(storeName string) string {
+	return filepath.Join(config.FilesystemPathToStores, storeName)
+}
+
+//TransformObjectToLoadedObject transform an object into an loadedObject
+func TransformObjectToLoadedObject[T, R any](object T) (R, error) {
+	var loadedObject R
+
+	serializedData, err := json.Marshal(object)
+	if err != nil {
+		return loadedObject, err
+	}
+
+	err = json.Unmarshal(serializedData, &loadedObject)
+	if err != nil {
+		return loadedObject, err
+	}
+
+	return loadedObject, err
+}
+
+//GetStoreFilenameForUUID returns the full filename for a given pndUUID and suffix
+func GetStoreFilenameForUUID(pndUUID uuid.UUID, deviceFilenameSuffix string) string {
+	return pndUUID.String() + "-" + deviceFilenameSuffix
+}
diff --git a/scripts/test-add-device.sh b/scripts/test-add-device.sh
index 72cb5acfd01275b8b4003bc3309c07cf717e0d65..5268009a17c5c48b410fa39fe6d7f733f9b77148 100755
--- a/scripts/test-add-device.sh
+++ b/scripts/test-add-device.sh
@@ -1,4 +1,3 @@
 ./artifacts/gosdnc init --controller 127.0.0.1:55055
 ./artifacts/gosdnc device create -a 172.100.0.11:6030 -u admin -p admin --name='test-ceos-1' --type csbi
 ./artifacts/gosdnc device list
-
diff --git a/scripts/test-add-pnd.sh b/scripts/test-add-pnd.sh
index 75704be2ec5b3d7ac6e220acbdd506bfb2a6b256..cee5db7f1317de6858600ac5b1d297ca35ad2dbd 100755
--- a/scripts/test-add-pnd.sh
+++ b/scripts/test-add-pnd.sh
@@ -1,4 +1,3 @@
 ./artifacts/gosdnc init --controller 127.0.0.1:55055
 ./artifacts/gosdnc pnd create --name test-pnd-1 test
-./artifacts/gosdnc device list
-
+./artifacts/gosdnc list
diff --git a/scripts/test-list-pnd.sh b/scripts/test-list-pnd.sh
new file mode 100755
index 0000000000000000000000000000000000000000..c96335f56cc2bb7394e8ba408145367e5f3c0560
--- /dev/null
+++ b/scripts/test-list-pnd.sh
@@ -0,0 +1,2 @@
+./artifacts/gosdnc init --controller 127.0.0.1:55055
+./artifacts/gosdnc list