diff --git a/controller/api/initialise_test.go b/controller/api/initialise_test.go
index c9363a7f44540d527caa8c04cfcc441645307752..ab531d3d8232d26653292413ffab973450a70921 100644
--- a/controller/api/initialise_test.go
+++ b/controller/api/initialise_test.go
@@ -43,7 +43,7 @@ const sbiID = "f6fd4b35-f039-4111-9156-5e4501bb8a5a"
 const ondID = "7e0ed8cc-ebf5-46fa-9794-741494914883"
 
 var pndStore networkdomain.PndStore
-var sbiStore southbound.SbiStore
+var sbiStore southbound.Store
 var lis *bufconn.Listener
 var pndUUID uuid.UUID
 var sbiUUID uuid.UUID
diff --git a/controller/interfaces/device/device.go b/controller/interfaces/device/device.go
index 55481cad37415c98335fe23ade9d29e70a0a3767..84a5dce80863728e8b53525656cd4965dbdc1ee3 100644
--- a/controller/interfaces/device/device.go
+++ b/controller/interfaces/device/device.go
@@ -27,3 +27,25 @@ type Details struct {
 	Address         string
 	TransportOption *tpb.TransportOption
 }
+
+// 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"`
+	// Name represents the name of the LoadedDevice.
+	Name string `json:"name,omitempty"`
+	// TransportType represent the type of the transport in use of the LoadedDevice.
+	TransportType string `json:"transport_type,omitempty" bson:"transport_type,omitempty"`
+	// TransportAddress represents the address from which the device can be reached via the transport method.
+	TransportAddress string `json:"transport_address,omitempty" bson:"transport_address,omitempty"`
+	// TransportUsername is used for authentication via the transport method in use.
+	TransportUsername string `json:"transport_username,omitempty" bson:"transport_username,omitempty"`
+	// TransportPassword is used for authentication via the transport method in use.
+	TransportPassword   string `json:"transport_password,omitempty" bson:"transport_password,omitempty"`
+	TransportOptionCsbi bool   `json:"transport_option_csbi,omitempty" bson:"transport_option_csbi,omitempty"`
+
+	// SBI indicates the southbound interface, which is used by this device as UUID.
+	SBI   string `json:"sbi"`
+	Model string `json:"model,omitempty" bson:"model,omitempty"`
+}
diff --git a/controller/interfaces/device/deviceService.go b/controller/interfaces/device/deviceService.go
new file mode 100644
index 0000000000000000000000000000000000000000..23417157302cedcb024cc94d68bbefb37e271d15
--- /dev/null
+++ b/controller/interfaces/device/deviceService.go
@@ -0,0 +1,14 @@
+package device
+
+import (
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+)
+
+// Service describes an interface for device service implementations.
+type Service interface {
+	Add(Device) error
+	Update(Device) error
+	Delete(Device) error
+	Get(store.Query) (Device, error)
+	GetAll() ([]Device, error)
+}
diff --git a/controller/interfaces/device/deviceStore.go b/controller/interfaces/device/deviceStore.go
index 10a056771883b3bd4886050ab25f82c099829c12..6fba480e52fc2f6f0af030c6f69b0cf42c8804bb 100644
--- a/controller/interfaces/device/deviceStore.go
+++ b/controller/interfaces/device/deviceStore.go
@@ -6,9 +6,9 @@ import (
 
 // Store describes an interface for device store implementations.
 type Store interface {
-	Add(d Device) error
-	Update(d Device) error
+	Add(Device) error
+	Update(Device) error
 	Delete(Device) error
-	Get(store.Query) (Device, error)
-	GetAll() ([]Device, error)
+	Get(store.Query) (LoadedDevice, error)
+	GetAll() ([]LoadedDevice, error)
 }
diff --git a/controller/interfaces/southbound/Service.go b/controller/interfaces/southbound/Service.go
new file mode 100644
index 0000000000000000000000000000000000000000..763bd7a46f8568cffd9a10fff92c3f95c5a5cece
--- /dev/null
+++ b/controller/interfaces/southbound/Service.go
@@ -0,0 +1,13 @@
+package southbound
+
+import (
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+)
+
+// Service describes an interface for sbi service implementations.
+type Service interface {
+	Add(SouthboundInterface) error
+	Delete(SouthboundInterface) error
+	Get(store.Query) (SouthboundInterface, error)
+	GetAll() ([]SouthboundInterface, error)
+}
diff --git a/controller/interfaces/southbound/sbi.go b/controller/interfaces/southbound/sbi.go
index 485a54ced2951a2b66ec01ec56ee3839f9df6e04..ffad0638adc2923438f44aa8ee9e6bc9d78dd43a 100644
--- a/controller/interfaces/southbound/sbi.go
+++ b/controller/interfaces/southbound/sbi.go
@@ -25,3 +25,11 @@ type SouthboundInterface interface { // nolint
 	Unmarshal([]byte, *gpb.Path, ygot.ValidatedGoStruct, ...ytypes.UnmarshalOpt) error
 	Name() string
 }
+
+// LoadedSbi represents a Southbound Interface that was loaded by using
+// the Load() method of the SbiStore.
+type LoadedSbi struct {
+	ID   string   `json:"_id" bson:"_id"`
+	Type spb.Type `bson:"type"`
+	Path string   `json:"path,omitempty"`
+}
diff --git a/controller/interfaces/southbound/sbiStore.go b/controller/interfaces/southbound/sbiStore.go
index bf69ec54b335336f66782a6f8fb70f8e8f549933..8c33372cefd13764b1bb23bb71275ffe2fbba943 100644
--- a/controller/interfaces/southbound/sbiStore.go
+++ b/controller/interfaces/southbound/sbiStore.go
@@ -4,10 +4,10 @@ import (
 	"code.fbi.h-da.de/danet/gosdn/controller/store"
 )
 
-// SbiStore describes an interface for sbi store implementations.
-type SbiStore interface {
+// Store describes an interface for sbi store implementations.
+type Store interface {
 	Add(SouthboundInterface) error
 	Delete(SouthboundInterface) error
-	Get(store.Query) (SouthboundInterface, error)
-	GetAll() ([]SouthboundInterface, error)
+	Get(store.Query) (LoadedSbi, error)
+	GetAll() ([]LoadedSbi, error)
 }
diff --git a/controller/northbound/server/pnd_test.go b/controller/northbound/server/pnd_test.go
index f95be5acc5af3975b87e3dd3d8151a57c5181466..b2acf2d7f3ddcbaa68d7f3dc2b9743850adb45d7 100644
--- a/controller/northbound/server/pnd_test.go
+++ b/controller/northbound/server/pnd_test.go
@@ -44,7 +44,7 @@ var committedChangeUUID uuid.UUID
 var deviceUUID uuid.UUID
 var mockPnd *mocks.NetworkDomain
 var mockDevice device.Device
-var sbiStore southbound.SbiStore
+var sbiStore southbound.Store
 
 func callback(id uuid.UUID, ch chan device.Details) {
 	// Need for pnd creation, but not needed for this test case.
diff --git a/controller/nucleus/databaseDeviceStore.go b/controller/nucleus/databaseDeviceStore.go
index fecf9f09ee1ba433518a77d2628dddf8aaa2115c..5ebf57278af54b36dca3cecc4db6f177fabf6d8d 100644
--- a/controller/nucleus/databaseDeviceStore.go
+++ b/controller/nucleus/databaseDeviceStore.go
@@ -3,10 +3,7 @@ package nucleus
 import (
 	"fmt"
 
-	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/interfaces/southbound"
 	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/database"
 	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
 	"code.fbi.h-da.de/danet/gosdn/controller/store"
@@ -15,58 +12,44 @@ import (
 	"go.mongodb.org/mongo-driver/mongo/options"
 
 	"github.com/google/uuid"
-	"github.com/openconfig/ygot/ygot"
 	log "github.com/sirupsen/logrus"
 )
 
 // DatabaseDeviceStore is used to store Devices
 type DatabaseDeviceStore struct {
 	storeName string
-	sbiStore  southbound.SbiStore
 }
 
 // NewDatabaseDeviceStore returns a DeviceStore
-func NewDatabaseDeviceStore(pndUUID uuid.UUID, sbiStore southbound.SbiStore) device.Store {
+func NewDatabaseDeviceStore(pndUUID uuid.UUID) device.Store {
 	return &DatabaseDeviceStore{
 		storeName: fmt.Sprintf("device-store-%s.json", pndUUID.String()),
-		sbiStore:  sbiStore,
 	}
 }
 
 // Get takes a Device's UUID or name and returns the Device.
-func (s *DatabaseDeviceStore) Get(query store.Query) (device.Device, error) {
-	var loadedDevice LoadedDevice
-	var err error
+func (s *DatabaseDeviceStore) Get(query store.Query) (device.LoadedDevice, error) {
+	var loadedDevice device.LoadedDevice
 
 	if query.ID.String() != "" {
-		loadedDevice, err = s.getByID(query.ID)
+		loadedDevice, err := s.getByID(query.ID)
 		if err != nil {
-			return nil, errors.ErrCouldNotFind{StoreName: deviceStoreName}
+			return loadedDevice, errors.ErrCouldNotFind{StoreName: deviceStoreName}
 		}
 
-		device, err := s.createDeviceFromStore(loadedDevice)
-		if err != nil {
-			return nil, err
-		}
-
-		return device, nil
+		return loadedDevice, nil
 	}
 
-	loadedDevice, err = s.getByName(query.Name)
+	loadedDevice, err := s.getByName(query.Name)
 	if err != nil {
-		return nil, errors.ErrCouldNotFind{StoreName: deviceStoreName}
-	}
-
-	device, err := s.createDeviceFromStore(loadedDevice)
-	if err != nil {
-		return nil, err
+		return loadedDevice, errors.ErrCouldNotFind{StoreName: deviceStoreName}
 	}
 
-	return device, nil
+	return loadedDevice, nil
 }
 
-func (s *DatabaseDeviceStore) getByID(idOfDevice uuid.UUID) (LoadedDevice, error) {
-	var loadedDevice LoadedDevice
+func (s *DatabaseDeviceStore) getByID(idOfDevice uuid.UUID) (device.LoadedDevice, error) {
+	var loadedDevice device.LoadedDevice
 
 	client, ctx, cancel := database.GetMongoConnection()
 	defer cancel()
@@ -88,8 +71,8 @@ func (s *DatabaseDeviceStore) getByID(idOfDevice uuid.UUID) (LoadedDevice, error
 	return loadedDevice, nil
 }
 
-func (s *DatabaseDeviceStore) getByName(nameOfDevice string) (LoadedDevice, error) {
-	var loadedDevice LoadedDevice
+func (s *DatabaseDeviceStore) getByName(nameOfDevice string) (device.LoadedDevice, error) {
+	var loadedDevice device.LoadedDevice
 
 	client, ctx, cancel := database.GetMongoConnection()
 	defer cancel()
@@ -112,9 +95,8 @@ func (s *DatabaseDeviceStore) getByName(nameOfDevice string) (LoadedDevice, erro
 }
 
 // GetAll returns all stored devices.
-func (s *DatabaseDeviceStore) GetAll() ([]device.Device, error) {
-	var loadedDevices []LoadedDevice
-	var devices []device.Device
+func (s *DatabaseDeviceStore) GetAll() ([]device.LoadedDevice, error) {
+	var loadedDevices []device.LoadedDevice
 
 	client, ctx, cancel := database.GetMongoConnection()
 	defer cancel()
@@ -135,16 +117,7 @@ func (s *DatabaseDeviceStore) GetAll() ([]device.Device, error) {
 		return nil, errors.ErrCouldNotMarshall{StoreName: pndStoreName}
 	}
 
-	for _, loadedDevice := range loadedDevices {
-		device, err := s.createDeviceFromStore(loadedDevice)
-		if err != nil {
-			return nil, err
-		}
-
-		devices = append(devices, device)
-	}
-
-	return devices, nil
+	return loadedDevices, nil
 }
 
 // Add adds a device to the device store.
@@ -166,7 +139,7 @@ func (s *DatabaseDeviceStore) Add(deviceToAdd device.Device) error {
 
 // Update updates a existing device.
 func (s *DatabaseDeviceStore) Update(deviceToUpdate device.Device) error {
-	var updatedLoadedDevice LoadedDevice
+	var updatedLoadedDevice device.LoadedDevice
 
 	client, ctx, cancel := database.GetMongoConnection()
 	defer cancel()
@@ -210,41 +183,3 @@ func (s *DatabaseDeviceStore) Delete(deviceToDelete device.Device) error {
 
 	return nil
 }
-
-func (s *DatabaseDeviceStore) createDeviceFromStore(loadedDevice LoadedDevice) (device.Device, error) {
-	sbiForDevice, err := s.sbiStore.Get(store.Query{ID: uuid.MustParse(loadedDevice.SBI)})
-	if err != nil {
-		return nil, err
-	}
-
-	d, err := NewDevice(
-		loadedDevice.Name,
-		uuid.MustParse(loadedDevice.DeviceID),
-		&tpb.TransportOption{
-			Address:  loadedDevice.TransportAddress,
-			Username: loadedDevice.TransportUsername,
-			Password: loadedDevice.TransportPassword,
-			TransportOption: &tpb.TransportOption_GnmiTransportOption{
-				GnmiTransportOption: &tpb.GnmiTransportOption{},
-			},
-			Type: spb.Type_TYPE_OPENCONFIG,
-		}, sbiForDevice)
-
-	if err != nil {
-		return nil, err
-	}
-
-	// Create 'root' path to be able to load the whole model from the store.
-	path, err := ygot.StringToPath("/", ygot.StructuredPath)
-	if err != nil {
-		return nil, err
-	}
-
-	// Use unmarshall from the devices SBI to unmarshall ygot json in go struct.
-	err = d.SBI().Unmarshal([]byte(loadedDevice.Model), path, d.GetModel())
-	if err != nil {
-		return nil, err
-	}
-
-	return d, nil
-}
diff --git a/controller/nucleus/databaseSbiStore.go b/controller/nucleus/databaseSbiStore.go
index abaaebc4f59ee3aaca95b17ebd6a27f4ed78b1d8..4c1ebe70f8226538a578e1a9165f02a50b4384c2 100644
--- a/controller/nucleus/databaseSbiStore.go
+++ b/controller/nucleus/databaseSbiStore.go
@@ -49,7 +49,7 @@ func (s *DatabaseSbiStore) Delete(item southbound.SouthboundInterface) error {
 		Collection(s.sbiStoreName).
 		DeleteOne(ctx, bson.D{primitive.E{Key: "_id", Value: item.ID().String()}})
 	if err != nil {
-		return errors.ErrCouldNotCreate{StoreName: sbiStoreName}
+		return errors.ErrCouldNotDelete{StoreName: sbiStoreName}
 	}
 
 	return nil
@@ -57,8 +57,8 @@ func (s *DatabaseSbiStore) Delete(item southbound.SouthboundInterface) error {
 
 // 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 *DatabaseSbiStore) Get(query store.Query) (southbound.SouthboundInterface, error) {
-	var loadedSbi *LoadedSbi
+func (s *DatabaseSbiStore) Get(query store.Query) (southbound.LoadedSbi, error) {
+	var loadedSbi southbound.LoadedSbi
 
 	client, ctx, cancel := database.GetMongoConnection()
 	defer cancel()
@@ -70,25 +70,22 @@ func (s *DatabaseSbiStore) Get(query store.Query) (southbound.SouthboundInterfac
 	collection := db.Collection(s.sbiStoreName)
 	result := collection.FindOne(ctx, bson.D{primitive.E{Key: "_id", Value: query.ID.String()}})
 	if result == nil {
-		return nil, nil
+		return loadedSbi, nil
 	}
 
 	err := result.Decode(&loadedSbi)
 	if err != nil {
 		log.Printf("Failed marshalling %v", err)
 
-		return nil, errors.ErrCouldNotMarshall{StoreName: sbiStoreName}
+		return loadedSbi, errors.ErrCouldNotMarshall{StoreName: sbiStoreName}
 	}
 
-	newSbi, _ := NewSBI(loadedSbi.Type, uuid.MustParse(loadedSbi.ID))
-
-	return newSbi, nil
+	return loadedSbi, nil
 }
 
 // GetAll returns all SBIs
-func (s *DatabaseSbiStore) GetAll() ([]southbound.SouthboundInterface, error) {
-	var loadedSbis []LoadedSbi
-	var sbis []southbound.SouthboundInterface
+func (s *DatabaseSbiStore) GetAll() ([]southbound.LoadedSbi, error) {
+	var loadedSbis []southbound.LoadedSbi
 
 	client, ctx, cancel := database.GetMongoConnection()
 	defer cancel()
@@ -109,18 +106,13 @@ func (s *DatabaseSbiStore) GetAll() ([]southbound.SouthboundInterface, error) {
 		return nil, errors.ErrCouldNotMarshall{StoreName: sbiStoreName}
 	}
 
-	for _, sbi := range loadedSbis {
-		newSbi, _ := NewSBI(sbi.Type, uuid.MustParse(sbi.ID))
-		sbis = append(sbis, newSbi)
-	}
-
-	return sbis, nil
+	return loadedSbis, nil
 }
 
 // GetSBI takes a SouthboundInterface's UUID or name and returns the SouthboundInterface. If the requested
 // SouthboundInterface does not exist an error is returned.
-func (s *DatabaseSbiStore) GetSBI(id uuid.UUID) (southbound.SouthboundInterface, error) {
-	var loadedSbi LoadedSbi
+func (s *DatabaseSbiStore) GetSBI(id uuid.UUID) (southbound.LoadedSbi, error) {
+	var loadedSbi southbound.LoadedSbi
 
 	client, ctx, cancel := database.GetMongoConnection()
 	defer cancel()
@@ -130,19 +122,17 @@ func (s *DatabaseSbiStore) GetSBI(id uuid.UUID) (southbound.SouthboundInterface,
 	collection := db.Collection(s.sbiStoreName)
 	result := collection.FindOne(ctx, bson.D{primitive.E{Key: "_id", Value: id.String()}})
 	if result == nil {
-		return nil, nil
+		return loadedSbi, nil
 	}
 
 	err := result.Decode(&loadedSbi)
 	if err != nil {
 		log.Printf("Failed marshalling %v", err)
 
-		return nil, errors.ErrCouldNotMarshall{StoreName: sbiStoreName}
+		return loadedSbi, errors.ErrCouldNotMarshall{StoreName: sbiStoreName}
 	}
 
-	newSbi, err := NewSBI(loadedSbi.Type, uuid.MustParse(loadedSbi.ID))
-
-	return newSbi, nil
+	return loadedSbi, nil
 }
 
 func getSbiTypeFromString(sbiTypeAsString string) spb.Type {
diff --git a/controller/nucleus/deviceService.go b/controller/nucleus/deviceService.go
new file mode 100644
index 0000000000000000000000000000000000000000..6679b974e63cbd4c9cc7360271da2152a2399830
--- /dev/null
+++ b/controller/nucleus/deviceService.go
@@ -0,0 +1,136 @@
+package nucleus
+
+import (
+	"fmt"
+
+	spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
+	"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"
+	"github.com/openconfig/ygot/ygot"
+
+	tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
+)
+
+// DeviceService provides a device service implementation.
+// This services provides abstraction between the user (e.g a PND) and the matching store (e.g. deviceStore)
+type DeviceService struct {
+	deviceStore device.Store
+	sbiService  southbound.Service
+}
+
+// NewDeviceService creates a device service.
+func NewDeviceService(deviceStore device.Store, sbiService southbound.Service) device.Service {
+	return &DeviceService{
+		deviceStore: deviceStore,
+		sbiService:  sbiService,
+	}
+}
+
+// Get takes a Device's UUID or name and returns the Device.
+func (s *DeviceService) Get(query store.Query) (device.Device, error) {
+	loadedDevice, err := s.deviceStore.Get(query)
+	if err != nil {
+		return nil, err
+	}
+
+	device, err := s.createDeviceFromStore(loadedDevice)
+	if err != nil {
+		return nil, err
+	}
+
+	return device, nil
+}
+
+// GetAll returns all stored devices.
+func (s *DeviceService) GetAll() ([]device.Device, error) {
+	var devices []device.Device
+
+	loadedDevices, err := s.deviceStore.GetAll()
+	if err != nil {
+		return nil, err
+	}
+
+	for _, loadedDevice := range loadedDevices {
+		device, err := s.createDeviceFromStore(loadedDevice)
+		if err != nil {
+			return nil, err
+		}
+
+		devices = append(devices, device)
+	}
+
+	return devices, nil
+}
+
+// Add adds a device to the device store.
+func (s *DeviceService) Add(deviceToAdd device.Device) error {
+	err := s.deviceStore.Add(deviceToAdd)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Update updates a existing device.
+func (s *DeviceService) Update(deviceToUpdate device.Device) error {
+	err := s.deviceStore.Update(deviceToUpdate)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Delete deletes a device from the device store.
+func (s *DeviceService) Delete(deviceToDelete device.Device) error {
+	err := s.deviceStore.Delete(deviceToDelete)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (s *DeviceService) createDeviceFromStore(loadedDevice device.LoadedDevice) (device.Device, error) {
+	if loadedDevice.SBI == "" {
+		return nil, fmt.Errorf("no sbi found for device")
+	}
+
+	sbiForDevice, err := s.sbiService.Get(store.Query{ID: uuid.MustParse(loadedDevice.SBI)})
+	if err != nil {
+		return nil, err
+	}
+
+	d, err := NewDevice(
+		loadedDevice.Name,
+		uuid.MustParse(loadedDevice.DeviceID),
+		&tpb.TransportOption{
+			Address:  loadedDevice.TransportAddress,
+			Username: loadedDevice.TransportUsername,
+			Password: loadedDevice.TransportPassword,
+			TransportOption: &tpb.TransportOption_GnmiTransportOption{
+				GnmiTransportOption: &tpb.GnmiTransportOption{},
+			},
+			Type: spb.Type_TYPE_OPENCONFIG,
+		}, sbiForDevice)
+	if err != nil {
+		return nil, err
+	}
+
+	// Create 'root' path to be able to load the whole model from the store.
+	path, err := ygot.StringToPath("/", ygot.StructuredPath)
+	if err != nil {
+		return nil, err
+	}
+
+	// Use unmarshall from the devices SBI to unmarshall ygot json in go struct.
+	err = d.SBI().Unmarshal([]byte(loadedDevice.Model), path, d.GetModel())
+	if err != nil {
+		return nil, err
+	}
+
+	return d, nil
+}
diff --git a/controller/nucleus/deviceService_test.go b/controller/nucleus/deviceService_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..b4ee228dd0d2475a84f47077fb9ad6627a95e5b5
--- /dev/null
+++ b/controller/nucleus/deviceService_test.go
@@ -0,0 +1,109 @@
+package nucleus
+
+import (
+	"testing"
+
+	"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/mocks"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+	"github.com/google/uuid"
+
+	spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound"
+)
+
+func getMockDevice(deviceID uuid.UUID, sbi southbound.SouthboundInterface) device.Device {
+	return &CommonDevice{
+		UUID:      deviceID,
+		Model:     sbi.Schema().Root,
+		sbi:       sbi,
+		transport: &mocks.Transport{},
+	}
+}
+
+func getDeviceTestStores(t *testing.T, deviceID uuid.UUID) (device.Service, southbound.Service, device.Device, southbound.SouthboundInterface) {
+	sbiStore := NewMemorySbiStore()
+	deviceStore := NewMemoryDeviceStore()
+	sbiService := NewSbiService(sbiStore)
+	deviceService := NewDeviceService(
+		deviceStore,
+		sbiService,
+	)
+
+	sbi, err := NewSBI(spb.Type_TYPE_OPENCONFIG)
+	if err != nil {
+		t.Error("could not create sbi")
+	}
+
+	err = sbiService.Add(sbi)
+	if err != nil {
+		t.Error("could not add sbi")
+	}
+
+	mockDevice := getMockDevice(deviceID, sbi)
+	err = deviceService.Add(mockDevice)
+	if err != nil {
+		t.Error("could not add device")
+	}
+
+	return deviceService, sbiService, mockDevice, sbi
+}
+
+func TestDeviceService_Get(t *testing.T) {
+	deviceID := uuid.New()
+
+	deviceService, _, mockDevice, _ := getDeviceTestStores(t, deviceID)
+
+	device, err := deviceService.Get(store.Query{
+		ID:   mockDevice.ID(),
+		Name: mockDevice.Name(),
+	})
+	if err != nil {
+		t.Error("could not get device")
+	}
+
+	if mockDevice.ID() != device.ID() {
+		t.Errorf("Expected ID=%s, got %s", mockDevice.ID(), device.ID())
+	}
+}
+
+func TestDeviceService_Delete(t *testing.T) {
+	deviceID := uuid.New()
+
+	deviceService, _, mockDevice, _ := getDeviceTestStores(t, deviceID)
+
+	device, err := deviceService.Get(store.Query{
+		ID:   mockDevice.ID(),
+		Name: mockDevice.Name(),
+	})
+	if err != nil {
+		t.Error("could not get device")
+	}
+
+	err = deviceService.Delete(device)
+	if err != nil {
+		t.Error("could not delete device")
+	}
+}
+
+func TestDeviceService_GetAll(t *testing.T) {
+	deviceID := uuid.New()
+	deviceID2 := uuid.New()
+
+	deviceService, _, _, sbi := getDeviceTestStores(t, deviceID)
+	mockDevice2 := getMockDevice(deviceID2, sbi)
+
+	err := deviceService.Add(mockDevice2)
+	if err != nil {
+		t.Error("could not add device")
+	}
+
+	devices, err := deviceService.GetAll()
+	if err != nil {
+		t.Error("could not get all devices")
+	}
+
+	if len(devices) != 2 {
+		t.Errorf("Expected len(devices)=2, got %d", len(devices))
+	}
+}
diff --git a/controller/nucleus/deviceStore.go b/controller/nucleus/deviceStore.go
index d47f4527e0b9e1e88800a8f3127430a651fc0665..04fa24ba7b03bd53f19292c272d464bf2d3cf3cd 100644
--- a/controller/nucleus/deviceStore.go
+++ b/controller/nucleus/deviceStore.go
@@ -18,55 +18,27 @@ const (
 // DeviceStore is used to store Devices
 type DeviceStore struct {
 	storeName string
-	sbiStore  southbound.SbiStore
-}
-
-// 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,omitempty"`
-	// Name represents the name of the LoadedDevice.
-	Name string `json:"name,omitempty"`
-	// TransportType represent the type of the transport in use of the LoadedDevice.
-	TransportType string `json:"transport_type,omitempty" bson:"transport_type,omitempty"`
-	// TransportAddress represents the address from which the device can be reached via the transport method.
-	TransportAddress string `json:"transport_address,omitempty" bson:"transport_address,omitempty"`
-	// TransportUsername is used for authentication via the transport method in use.
-	TransportUsername string `json:"transport_username,omitempty" bson:"transport_username,omitempty"`
-	// TransportPassword is used for authentication via the transport method in use.
-	TransportPassword   string `json:"transport_password,omitempty" bson:"transport_password,omitempty"`
-	TransportOptionCsbi bool   `json:"transport_option_csbi,omitempty" bson:"transport_option_csbi,omitempty"`
-
-	// SBI indicates the southbound interface, which is used by this device as UUID.
-	SBI   string `json:"sbi,omitempty"`
-	Model string `json:"model,omitempty" bson:"model,omitempty"`
-}
-
-// ID returns the ID of the LoadedDevice as UUID.
-func (ld LoadedDevice) ID() uuid.UUID {
-	return uuid.MustParse(ld.DeviceID)
+	sbiStore  southbound.Store
 }
 
 // NewDeviceStore returns a DeviceStore
-func NewDeviceStore(pndUUID uuid.UUID, sbiStore southbound.SbiStore) device.Store {
+func NewDeviceStore(pndUUID uuid.UUID) device.Store {
 	storeMode := store.GetStoreMode()
 	log.Debugf("StoreMode: %s", storeMode)
 
 	switch storeMode {
 	case store.Filesystem:
-		store := NewGenericStore[device.Device]()
+		store := NewMemoryDeviceStore()
 
-		return &store
+		return store
 	case store.Database:
 		return &DatabaseDeviceStore{
 			storeName: fmt.Sprintf("device-store-%s.json", pndUUID.String()),
-			sbiStore:  sbiStore,
 		}
 	case store.Memory:
-		store := NewGenericStore[device.Device]()
+		store := NewMemoryDeviceStore()
 
-		return &store
+		return store
 	default:
 		return nil
 	}
diff --git a/controller/nucleus/errors/errors.go b/controller/nucleus/errors/errors.go
index abee04244bf3388beb97f3e0c48271b12bd0d55c..3e38ba8b6e7628b85d3f5811b574a97f5b6f43f3 100644
--- a/controller/nucleus/errors/errors.go
+++ b/controller/nucleus/errors/errors.go
@@ -195,3 +195,13 @@ type ErrCouldNotCreate struct {
 func (e ErrCouldNotCreate) Error() string {
 	return fmt.Sprintf("could not create %s", e.StoreName)
 }
+
+// ErrCouldNotDelete implements the Error interface and is called if a
+// stored item can not be deleted.
+type ErrCouldNotDelete struct {
+	StoreName string
+}
+
+func (e ErrCouldNotDelete) Error() string {
+	return fmt.Sprintf("could not delete %s", e.StoreName)
+}
diff --git a/controller/nucleus/genericStore.go b/controller/nucleus/genericService.go
similarity index 61%
rename from controller/nucleus/genericStore.go
rename to controller/nucleus/genericService.go
index fe12bdc81b9a63f579ef837d1123134b45cede70..a794928e75c46e5ca8f0f07311f86759b616c313 100644
--- a/controller/nucleus/genericStore.go
+++ b/controller/nucleus/genericService.go
@@ -10,21 +10,22 @@ type storableConstraint interface {
 	Name() string
 }
 
-// GenericStore provides a in-memory implementation for multiple stores.
-type GenericStore[T storableConstraint] struct {
+// GenericService provides a in-memory implementation for multiple stores.
+type GenericService[T storableConstraint] struct {
 	Store           map[uuid.UUID]T
 	nameLookupTable map[string]uuid.UUID
 }
 
-// NewGenericStore returns a specific in-memory store for a type T.
-func NewGenericStore[T storableConstraint]() GenericStore[T] {
-	return GenericStore[T]{
+// NewGenericService returns a specific in-memory store for a type T.
+func NewGenericService[T storableConstraint]() GenericService[T] {
+	return GenericService[T]{
 		Store:           make(map[uuid.UUID]T),
 		nameLookupTable: make(map[string]uuid.UUID),
 	}
 }
 
-func (t *GenericStore[T]) Add(item T) error {
+// Add adds a item T
+func (t *GenericService[T]) Add(item T) error {
 	_, ok := t.Store[item.ID()]
 	if ok {
 		return nil
@@ -36,7 +37,8 @@ func (t *GenericStore[T]) Add(item T) error {
 	return nil
 }
 
-func (t *GenericStore[T]) Update(item T) error {
+// Update updates a item T
+func (t *GenericService[T]) Update(item T) error {
 	_, ok := t.Store[item.ID()]
 	if ok {
 		return nil
@@ -48,13 +50,15 @@ func (t *GenericStore[T]) Update(item T) error {
 	return nil
 }
 
-func (t *GenericStore[T]) Delete(item T) error {
+// Delete deletes a item T
+func (t *GenericService[T]) Delete(item T) error {
 	delete(t.Store, item.ID())
 
 	return nil
 }
 
-func (t *GenericStore[T]) Get(query store.Query) (T, error) {
+// Get gets a item T
+func (t *GenericService[T]) Get(query store.Query) (T, error) {
 	// First search for direct hit on UUID.
 	item, ok := t.Store[query.ID]
 	if !ok {
@@ -75,7 +79,8 @@ func (t *GenericStore[T]) Get(query store.Query) (T, error) {
 	return item, nil
 }
 
-func (t *GenericStore[T]) GetAll() ([]T, error) {
+// GetAll gets all items
+func (t *GenericService[T]) GetAll() ([]T, error) {
 	var allItems []T
 
 	for _, item := range t.Store {
diff --git a/controller/nucleus/initialise_test.go b/controller/nucleus/initialise_test.go
index 9f9146a1ff9c3fc4b58927480679c4d984092735..9feef90276b7d7a6dddc15102ecf33b0d5f57cb3 100644
--- a/controller/nucleus/initialise_test.go
+++ b/controller/nucleus/initialise_test.go
@@ -6,7 +6,6 @@ import (
 	"testing"
 
 	"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"
 
 	tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport"
@@ -150,14 +149,19 @@ func mockDevice() device.Device {
 }
 
 func newPnd() pndImplementation {
-	sbiStore := NewGenericStore[southbound.SouthboundInterface]()
-	deviceStore := NewGenericStore[device.Device]()
+	sbiStore := NewMemorySbiStore()
+	deviceStore := NewMemoryDeviceStore()
+	sbiService := NewSbiService(sbiStore)
+	deviceService := NewDeviceService(
+		deviceStore,
+		sbiService,
+	)
 
 	return pndImplementation{
 		Name:        "default",
 		Description: "default test pnd",
-		sbic:        &sbiStore,
-		devices:     &deviceStore,
+		sbic:        sbiService,
+		devices:     deviceService,
 		changes:     store.NewChangeStore(),
 		Id:          defaultPndID,
 	}
diff --git a/controller/nucleus/memoryDeviceStore.go b/controller/nucleus/memoryDeviceStore.go
new file mode 100644
index 0000000000000000000000000000000000000000..536bb6ea4502e5de931b31e3ae95a25c514dda62
--- /dev/null
+++ b/controller/nucleus/memoryDeviceStore.go
@@ -0,0 +1,111 @@
+package nucleus
+
+import (
+	"encoding/json"
+
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/device"
+	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+)
+
+// MemoryDeviceStore provides a in-memory implementation for devices.
+type MemoryDeviceStore struct {
+	Store           map[string]device.LoadedDevice
+	nameLookupTable map[string]string
+}
+
+// NewMemoryDeviceStore returns a specific in-memory store for devices.
+func NewMemoryDeviceStore() device.Store {
+	return &MemoryDeviceStore{
+		Store:           make(map[string]device.LoadedDevice),
+		nameLookupTable: make(map[string]string),
+	}
+}
+
+// Add adds a item to the store.
+func (t *MemoryDeviceStore) Add(item device.Device) error {
+	var device device.LoadedDevice
+
+	b, err := json.Marshal(item)
+	if err != nil {
+		return err
+	}
+	err = json.Unmarshal(b, &device)
+	if err != nil {
+		return err
+	}
+
+	_, ok := t.Store[device.DeviceID]
+	if ok {
+		return nil
+	}
+
+	t.Store[device.DeviceID] = device
+	t.nameLookupTable[item.Name()] = device.DeviceID
+
+	return nil
+}
+
+// Update updates a existing device.
+func (t *MemoryDeviceStore) Update(item device.Device) error {
+	_, ok := t.Store[item.ID().String()]
+	if ok {
+		return nil
+	}
+
+	var device device.LoadedDevice
+
+	b, err := json.Marshal(item)
+	if err != nil {
+		return err
+	}
+	err = json.Unmarshal(b, &device)
+	if err != nil {
+		return err
+	}
+
+	t.Store[item.ID().String()] = device
+	t.nameLookupTable[item.Name()] = item.ID().String()
+
+	return nil
+}
+
+// Delete deletes a device from the device store.
+func (t *MemoryDeviceStore) Delete(item device.Device) error {
+	delete(t.Store, item.ID().String())
+
+	return nil
+}
+
+// Get takes a Device's UUID or name and returns the Device.
+func (t *MemoryDeviceStore) Get(query store.Query) (device.LoadedDevice, error) {
+	// First search for direct hit on UUID.
+	item, ok := t.Store[query.ID.String()]
+	if !ok {
+		// Second search for name
+		id, ok := t.nameLookupTable[query.Name]
+		if !ok {
+			return item, errors.ErrCouldNotFind{StoreName: deviceStoreName}
+		}
+
+		item, ok := t.Store[id]
+		if !ok {
+			return item, errors.ErrCouldNotFind{StoreName: deviceStoreName}
+		}
+
+		return item, nil
+	}
+
+	return item, nil
+}
+
+// GetAll returns all stored devices.
+func (t *MemoryDeviceStore) GetAll() ([]device.LoadedDevice, error) {
+	var allItems []device.LoadedDevice
+
+	for _, item := range t.Store {
+		allItems = append(allItems, item)
+	}
+
+	return allItems, nil
+}
diff --git a/controller/nucleus/memorySbiStore.go b/controller/nucleus/memorySbiStore.go
new file mode 100644
index 0000000000000000000000000000000000000000..d9f1245026c8bbca4ee462d64bf25c70d6b40878
--- /dev/null
+++ b/controller/nucleus/memorySbiStore.go
@@ -0,0 +1,111 @@
+package nucleus
+
+import (
+	"encoding/json"
+
+	"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/store"
+)
+
+// MemorySbiStore provides a in-memory implementation for sbis.
+type MemorySbiStore struct {
+	Store           map[string]southbound.LoadedSbi
+	nameLookupTable map[string]string
+}
+
+// NewMemorySbiStore returns a specific in-memory store for a type T.
+func NewMemorySbiStore() southbound.Store {
+	return &MemorySbiStore{
+		Store:           make(map[string]southbound.LoadedSbi),
+		nameLookupTable: make(map[string]string),
+	}
+}
+
+// Add adds a item to the store.
+func (t *MemorySbiStore) Add(item southbound.SouthboundInterface) error {
+	var sbi southbound.LoadedSbi
+
+	b, err := json.Marshal(item)
+	if err != nil {
+		return err
+	}
+	err = json.Unmarshal(b, &sbi)
+	if err != nil {
+		return err
+	}
+
+	_, ok := t.Store[sbi.ID]
+	if ok {
+		return nil
+	}
+
+	t.Store[sbi.ID] = sbi
+	t.nameLookupTable[item.Name()] = sbi.ID
+
+	return nil
+}
+
+// Update updates a existing sbi.
+func (t *MemorySbiStore) Update(item southbound.SouthboundInterface) error {
+	_, ok := t.Store[item.ID().String()]
+	if ok {
+		return nil
+	}
+
+	var sbi southbound.LoadedSbi
+
+	b, err := json.Marshal(item)
+	if err != nil {
+		return err
+	}
+	err = json.Unmarshal(b, &sbi)
+	if err != nil {
+		return err
+	}
+
+	t.Store[item.ID().String()] = sbi
+	t.nameLookupTable[item.Name()] = item.ID().String()
+
+	return nil
+}
+
+// Delete deletes a sbi from the store.
+func (t *MemorySbiStore) Delete(item southbound.SouthboundInterface) error {
+	delete(t.Store, item.ID().String())
+
+	return nil
+}
+
+// Get takes a sbi's UUID or name and returns the sbi.
+func (t *MemorySbiStore) Get(query store.Query) (southbound.LoadedSbi, error) {
+	// First search for direct hit on UUID.
+	item, ok := t.Store[query.ID.String()]
+	if !ok {
+		// Second search for name
+		id, ok := t.nameLookupTable[query.Name]
+		if !ok {
+			return item, errors.ErrCouldNotDelete{StoreName: sbiStoreName}
+		}
+
+		item, ok := t.Store[id]
+		if !ok {
+			return item, errors.ErrCouldNotFind{StoreName: sbiStoreName}
+		}
+
+		return item, nil
+	}
+
+	return item, nil
+}
+
+// GetAll returns all stored sbis.
+func (t *MemorySbiStore) GetAll() ([]southbound.LoadedSbi, error) {
+	var allItems []southbound.LoadedSbi
+
+	for _, item := range t.Store {
+		allItems = append(allItems, item)
+	}
+
+	return allItems, nil
+}
diff --git a/controller/nucleus/principalNetworkDomain.go b/controller/nucleus/principalNetworkDomain.go
index 9f24bcc9f03017d2a79eba32cb1c50ba7c1a1d5f..3d23862bcc27251e1d8ddb82893b2bb9675b3ca6 100644
--- a/controller/nucleus/principalNetworkDomain.go
+++ b/controller/nucleus/principalNetworkDomain.go
@@ -52,6 +52,14 @@ func NewPND(
 	callback func(uuid.UUID, chan device.Details),
 ) (networkdomain.NetworkDomain, error) {
 	sbiStore := NewSbiStore(id)
+	deviceStore := NewDeviceStore(id)
+	changeStore := store.NewChangeStore()
+
+	sbiService := NewSbiService(sbiStore)
+	deviceService := NewDeviceService(
+		deviceStore,
+		sbiService,
+	)
 
 	changeStore, ok := changeStoreMap[id]
 	if !ok {
@@ -62,8 +70,8 @@ func NewPND(
 	pnd := &pndImplementation{
 		Name:        name,
 		Description: description,
-		sbic:        sbiStore,
-		devices:     NewDeviceStore(id, sbiStore),
+		sbic:        sbiService,
+		devices:     deviceService,
 		changes:     changeStore,
 		Id:          id,
 
@@ -87,8 +95,8 @@ func NewPND(
 type pndImplementation struct {
 	Name        string `json:"name,omitempty"`
 	Description string `json:"description,omitempty"`
-	sbic        southbound.SbiStore
-	devices     device.Store
+	sbic        southbound.Service
+	devices     device.Service
 	changes     *store.ChangeStore
 	//nolint
 	Id uuid.UUID `json:"id,omitempty"`
diff --git a/controller/nucleus/principalNetworkDomain_test.go b/controller/nucleus/principalNetworkDomain_test.go
index f6d58d02dab9cb0ebeb4c3a547a75f03242bcd08..2045bd626806c935b25c99e37b2eac0875ca46ac 100644
--- a/controller/nucleus/principalNetworkDomain_test.go
+++ b/controller/nucleus/principalNetworkDomain_test.go
@@ -195,8 +195,8 @@ func Test_pndImplementation_Destroy(t *testing.T) {
 	type fields struct {
 		name        string
 		description string
-		sbi         southbound.SbiStore
-		devices     device.Store
+		sbi         southbound.Service
+		devices     device.Service
 	}
 	tests := []struct {
 		name    string
@@ -254,23 +254,6 @@ func Test_pndImplementation_GetName(t *testing.T) {
 	}
 }
 
-// func Test_pndImplementation_GetSBIs(t *testing.T) {
-// 	pnd := newPnd()
-// 	tests := []struct {
-// 		name string
-// 		want []southbound.SouthboundInterface
-// 	}{
-// 		{name: "default", want: []southbound.SouthboundInterface{}},
-// 	}
-// 	for _, tt := range tests {
-// 		t.Run(tt.name, func(t *testing.T) {
-// 			if got, _ := pnd.GetSBIs(); !reflect.DeepEqual(got, tt.want) {
-// 				t.Errorf("GetSBIs() = %v, want %v", got, tt.want)
-// 			}
-// 		})
-// 	}
-// }
-
 func Test_pndImplementation_MarshalDevice(t *testing.T) {
 	type args struct {
 		uuid uuid.UUID
@@ -292,10 +275,19 @@ func Test_pndImplementation_MarshalDevice(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			pnd := newPnd()
+			sbi, err := NewSBI(spb.Type_TYPE_OPENCONFIG)
+			if err != nil {
+				t.Error("could not create sbi")
+			}
+
+			err = pnd.addSbi(sbi)
+			if err != nil {
+				t.Error("could not add sbi")
+			}
 			d := &CommonDevice{
 				UUID:      tt.args.uuid,
 				Model:     &openconfig.Device{},
-				sbi:       nil,
+				sbi:       sbi,
 				transport: nil,
 			}
 			if err := pnd.addDevice(d); err != nil {
@@ -327,25 +319,28 @@ func Test_pndImplementation_RemoveDevice(t *testing.T) {
 	}{
 		{name: "default", args: args{uuid: did}, wantErr: false},
 		{name: "fails", args: args{uuid: uuid.New()}, wantErr: true},
-		{name: "fails empty", args: args{uuid: did}, wantErr: true},
 	}
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			pnd := newPnd()
-			if tt.name != "fails empty" {
-				sbi, err := NewSBI(spb.Type_TYPE_OPENCONFIG)
-				if err != nil {
-					t.Error(err)
-					return
-				}
-				d := &CommonDevice{
-					UUID: did,
-					sbi:  sbi,
-				}
-				if err := pnd.addDevice(d); err != nil {
-					t.Error(err)
-				}
+			sbi, err := NewSBI(spb.Type_TYPE_OPENCONFIG)
+			if err != nil {
+				t.Error("could not create sbi")
+			}
+
+			err = pnd.addSbi(sbi)
+			if err != nil {
+				t.Error("could not add sbi")
+			}
+			d := &CommonDevice{
+				UUID:      did,
+				Model:     &openconfig.Device{},
+				sbi:       sbi,
+				transport: nil,
+			}
+			if err := pnd.addDevice(d); err != nil {
+				t.Error(err)
 			}
 			if err := pnd.RemoveDevice(tt.args.uuid); (err != nil) != tt.wantErr {
 				t.Errorf("RemoveDevice() error = %v, wantErr %v", err, tt.wantErr)
@@ -355,6 +350,67 @@ func Test_pndImplementation_RemoveDevice(t *testing.T) {
 }
 
 func Test_pndImplementation_RemoveSbi(t *testing.T) {
+	type args struct {
+		id uuid.UUID
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{name: "default", args: args{id: defaultSbiID}, wantErr: false},
+		{name: "fails", args: args{id: uuid.New()}, wantErr: true},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			sbiStore := NewSbiStore(defaultPndID)
+			deviceStore := NewDeviceStore(defaultPndID)
+			sbiService := NewSbiService(sbiStore)
+			deviceService := NewDeviceService(deviceStore, sbiService)
+
+			pnd := &pndImplementation{
+				Name:        "test-remove-sbi",
+				Description: "test-remove-sbi",
+				sbic:        sbiService,
+				devices:     deviceService,
+				Id:          defaultPndID,
+			}
+
+			sbi, err := NewSBI(spb.Type_TYPE_OPENCONFIG, defaultSbiID)
+			if err != nil {
+				t.Error("could not create sbi")
+			}
+
+			err = pnd.addSbi(sbi)
+			if err != nil {
+				t.Error("could not add sbi")
+			}
+
+			if err := pnd.RemoveSbi(tt.args.id); (err != nil) != tt.wantErr {
+				t.Errorf("RemoveSbi() error = %v, wantErr %v", err, tt.wantErr)
+			}
+
+			foundSbi, _ := pnd.sbic.Get(store.Query{ID: tt.args.id})
+			if foundSbi != nil {
+				t.Errorf("RemoveSbi() SBI still in SBI store %v", pnd.sbic)
+			}
+
+			if tt.name == "exclusively remove associated devices" {
+				allDevices, _ := pnd.devices.GetAll()
+				if len(allDevices) != 1 {
+					t.Errorf("RemoveSbi() non associated devices should remain in the storage %v", allDevices)
+				}
+			} else {
+				allDevices, _ := pnd.devices.GetAll()
+				if len(allDevices) != 0 {
+					t.Errorf("RemoveSbi() associated devices have not been removed correctly %v", len(allDevices))
+				}
+			}
+		})
+	}
+}
+
+func Test_pndImplementation_RemoveSbiWithAssociatedDevices(t *testing.T) {
 	opts := &tpb.TransportOption{
 		TransportOption: &tpb.TransportOption_GnmiTransportOption{
 			GnmiTransportOption: &tpb.GnmiTransportOption{},
@@ -368,49 +424,58 @@ func Test_pndImplementation_RemoveSbi(t *testing.T) {
 		args    args
 		wantErr bool
 	}{
-		{name: "default", args: args{id: defaultSbiID}, wantErr: false},
-		{name: "fails", args: args{id: uuid.New()}, wantErr: true},
-		{name: "fails empty", args: args{id: defaultSbiID}, wantErr: true},
 		{name: "exclusively remove associated devices", args: args{id: defaultSbiID}, wantErr: false},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			sbiStore := NewSbiStore(defaultPndID)
+			deviceStore := NewDeviceStore(defaultPndID)
+			sbiService := NewSbiService(sbiStore)
+			deviceService := NewDeviceService(deviceStore, sbiService)
 
 			pnd := &pndImplementation{
 				Name:        "test-remove-sbi",
 				Description: "test-remove-sbi",
-				sbic:        sbiStore,
-				devices:     NewDeviceStore(defaultPndID, sbiStore),
+				sbic:        sbiService,
+				devices:     deviceService,
 				Id:          defaultPndID,
 			}
-			if tt.name != "fails empty" && tt.name != "fails" {
-				if err := pnd.addSbi(&OpenConfig{id: defaultSbiID}); err != nil {
-					t.Error(err)
-				}
-				if err := pnd.AddDevice("associatedDevice", opts, tt.args.id); err != nil {
+
+			sbi, err := NewSBI(spb.Type_TYPE_OPENCONFIG, defaultSbiID)
+			if err != nil {
+				t.Error("could not create sbi")
+			}
+
+			err = pnd.addSbi(sbi)
+			if err != nil {
+				t.Error("could not add sbi")
+			}
+
+			if err := pnd.addSbi(&OpenConfig{id: defaultSbiID}); err != nil {
+				t.Error(err)
+			}
+			if err := pnd.AddDevice("associatedDevice", opts, tt.args.id); err != nil {
+				t.Error(err)
+			}
+			if err := pnd.AddDevice("associatedDevice2", opts, tt.args.id); err != nil {
+				t.Error(err)
+			}
+			if tt.name == "exclusively remove associated devices" {
+				newID := uuid.New()
+				if err := pnd.addSbi(&OpenConfig{id: newID}); err != nil {
 					t.Error(err)
 				}
-				if err := pnd.AddDevice("associatedDevice2", opts, tt.args.id); err != nil {
+				if err := pnd.AddDevice("associatedDevice2", opts, newID); err != nil {
 					t.Error(err)
 				}
-				if tt.name == "exclusively remove associated devices" {
-					newID := uuid.New()
-					if err := pnd.addSbi(&OpenConfig{id: newID}); err != nil {
-						t.Error(err)
-					}
-					if err := pnd.AddDevice("associatedDevice2", opts, newID); err != nil {
-						t.Error(err)
-					}
-				}
 			}
 
 			if err := pnd.RemoveSbi(tt.args.id); (err != nil) != tt.wantErr {
 				t.Errorf("RemoveSbi() error = %v, wantErr %v", err, tt.wantErr)
 			}
 
-			sbi, _ := pnd.sbic.Get(store.Query{ID: tt.args.id})
-			if sbi != nil {
+			foundSbi, _ := pnd.sbic.Get(store.Query{ID: tt.args.id})
+			if foundSbi != nil {
 				t.Errorf("RemoveSbi() SBI still in SBI store %v", pnd.sbic)
 			}
 
@@ -462,14 +527,42 @@ func Test_pndImplementation_Request(t *testing.T) {
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			deviceWithMockTransport := mockDevice()
-			pnd := newPnd()
-			transport := deviceWithMockTransport.Transport().(*mocks.Transport)
+			sbiService := NewGenericService[southbound.SouthboundInterface]()
+			deviceService := NewGenericService[device.Device]()
+
+			pnd := pndImplementation{
+				Name:        "default",
+				Description: "default test pnd",
+				sbic:        &sbiService,
+				devices:     &deviceService,
+				changes:     store.NewChangeStore(),
+				Id:          defaultPndID,
+			}
+
+			sbi, err := NewSBI(spb.Type_TYPE_OPENCONFIG)
+			if err != nil {
+				t.Error("could not create sbi")
+			}
+
+			err = pnd.addSbi(sbi)
+			if err != nil {
+				t.Error("could not add sbi")
+			}
+
+			transport := mocks.Transport{}
 			transport.On("Get", mockContext, mock.Anything).Return(&gpb.GetResponse{}, tt.args.rErr)
 			transport.On("ProcessResponse", mock.Anything, mock.Anything, mock.Anything).Return(tt.args.rErr)
+
+			deviceWithMockTransport := &CommonDevice{
+				UUID:      mdid,
+				Model:     &openconfig.Device{},
+				sbi:       sbi,
+				transport: &transport,
+			}
+
 			_ = pnd.addDevice(deviceWithMockTransport)
 
-			_, err := pnd.Request(tt.args.uuid, tt.args.path)
+			_, err = pnd.Request(tt.args.uuid, tt.args.path)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("Request() error = %v, wantErr %v", err, tt.wantErr)
 			}
@@ -518,17 +611,41 @@ func Test_pndImplementation_RequestAll(t *testing.T) {
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			deviceWithMockTransport := mockDevice()
-			pnd := newPnd()
-			tr := deviceWithMockTransport.Transport().(*mocks.Transport)
-			tr.On("Get", mockContext, mock.Anything).Return(&gpb.GetResponse{}, tt.args.rErr)
-			tr.On("ProcessResponse", mock.Anything, mock.Anything, mock.Anything).Return(tt.args.rErr)
+			sbiService := NewGenericService[southbound.SouthboundInterface]()
+			deviceService := NewGenericService[device.Device]()
 
-			_ = pnd.addDevice(deviceWithMockTransport)
-			if err := pnd.RequestAll(tt.args.path); (err != nil) != tt.wantErr {
-				t.Errorf("RequestAll() error = %v, wantErr %v", err, tt.wantErr)
+			pnd := pndImplementation{
+				Name:        "default",
+				Description: "default test pnd",
+				sbic:        &sbiService,
+				devices:     &deviceService,
+				changes:     store.NewChangeStore(),
+				Id:          defaultPndID,
+			}
+
+			sbi, err := NewSBI(spb.Type_TYPE_OPENCONFIG)
+			if err != nil {
+				t.Error("could not create sbi")
+			}
+
+			err = pnd.addSbi(sbi)
+			if err != nil {
+				t.Error("could not add sbi")
 			}
 
+			transport := mocks.Transport{}
+			transport.On("Get", mockContext, mock.Anything).Return(&gpb.GetResponse{}, tt.args.rErr)
+			transport.On("ProcessResponse", mock.Anything, mock.Anything, mock.Anything).Return(tt.args.rErr)
+
+			deviceWithMockTransport := &CommonDevice{
+				UUID:      mdid,
+				Model:     &openconfig.Device{},
+				sbi:       sbi,
+				transport: &transport,
+			}
+
+			_ = pnd.addDevice(deviceWithMockTransport)
+
 			device, _ := pnd.devices.Get(store.Query{ID: mdid})
 			if device == nil {
 				return
@@ -672,7 +789,12 @@ func Test_pndImplementation_GetDevice(t *testing.T) {
 		t.Errorf("NewSBI() error = %v", err)
 		return
 	}
-	d, err := NewDevice("", uuid.Nil, newGnmiTransportOptions(), sbi)
+	err = pnd.addSbi(sbi)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	d, err := NewDevice("default", did, newGnmiTransportOptions(), sbi)
 	if err != nil {
 		t.Error(err)
 		return
@@ -681,6 +803,7 @@ func Test_pndImplementation_GetDevice(t *testing.T) {
 		t.Error(err)
 		return
 	}
+
 	type args struct {
 		uuid uuid.UUID
 	}
@@ -692,7 +815,7 @@ func Test_pndImplementation_GetDevice(t *testing.T) {
 	}{
 		{
 			name:    "default",
-			args:    args{uuid: d.ID()},
+			args:    args{uuid: did},
 			want:    sbi.Schema().Root,
 			wantErr: false,
 		},
@@ -720,18 +843,23 @@ func Test_pndImplementation_GetDevice(t *testing.T) {
 }
 
 func Test_pndImplementation_GetDeviceByName(t *testing.T) {
-	p := newPnd()
+	pnd := newPnd()
 	sbi, err := NewSBI(spb.Type_TYPE_OPENCONFIG)
 	if err != nil {
 		t.Errorf("NewSBI() error = %v", err)
 		return
 	}
-	d, err := NewDevice("my-device", uuid.Nil, newGnmiTransportOptions(), sbi)
+	err = pnd.addSbi(sbi)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	d, err := NewDevice("my-device", did, newGnmiTransportOptions(), sbi)
 	if err != nil {
 		t.Error(err)
 		return
 	}
-	if err = p.addDevice(d); err != nil {
+	if err = pnd.addDevice(d); err != nil {
 		t.Error(err)
 		return
 	}
@@ -759,7 +887,7 @@ func Test_pndImplementation_GetDeviceByName(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			foundDevice, err := p.GetDevice(tt.args.name)
+			foundDevice, err := pnd.GetDevice(tt.args.name)
 			if (err != nil) != tt.wantErr {
 				t.Errorf("GetDeviceByName() error = %v, wantErr %v", err, tt.wantErr)
 				return
@@ -790,7 +918,18 @@ func Test_pndImplementation_Confirm(t *testing.T) {
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			pnd := newPnd()
+			sbiService := NewGenericService[southbound.SouthboundInterface]()
+			deviceService := NewGenericService[device.Device]()
+
+			pnd := pndImplementation{
+				Name:        "default",
+				Description: "default test pnd",
+				sbic:        &sbiService,
+				devices:     &deviceService,
+				changes:     store.NewChangeStore(),
+				Id:          defaultPndID,
+			}
+
 			d := mockDevice()
 			tr := d.Transport().(*mocks.Transport)
 			tr.On("Set", mockContext, mock.Anything, mock.Anything).Return(nil)
diff --git a/controller/nucleus/sbiService.go b/controller/nucleus/sbiService.go
new file mode 100644
index 0000000000000000000000000000000000000000..a92a3be32b159ee32173bbf295adab6ad7a6e61f
--- /dev/null
+++ b/controller/nucleus/sbiService.go
@@ -0,0 +1,84 @@
+package nucleus
+
+import (
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+	"github.com/google/uuid"
+)
+
+// SbiService provides a sbi service implementation.
+type SbiService struct {
+	sbiStore southbound.Store
+}
+
+// NewSbiService creates a sbi service.
+func NewSbiService(sbiStore southbound.Store) southbound.Service {
+	return &SbiService{
+		sbiStore: sbiStore,
+	}
+}
+
+// Get takes a SBI's UUID or name and returns the SBI.
+func (s *SbiService) Get(query store.Query) (southbound.SouthboundInterface, error) {
+	loadedSbi, err := s.sbiStore.Get(query)
+	if err != nil {
+		return nil, err
+	}
+
+	device, err := s.createSbiFromStore(loadedSbi)
+	if err != nil {
+		return nil, err
+	}
+
+	return device, nil
+}
+
+// GetAll returns all stored SBIs.
+func (s *SbiService) GetAll() ([]southbound.SouthboundInterface, error) {
+	var sbis []southbound.SouthboundInterface
+
+	loadedSbis, err := s.sbiStore.GetAll()
+	if err != nil {
+		return nil, err
+	}
+
+	for _, loadedSbi := range loadedSbis {
+		sbi, err := s.createSbiFromStore(loadedSbi)
+		if err != nil {
+			return nil, err
+		}
+
+		sbis = append(sbis, sbi)
+	}
+
+	return sbis, nil
+}
+
+// Add adds a sbi to the sbi store.
+func (s *SbiService) Add(sbiToAdd southbound.SouthboundInterface) error {
+	err := s.sbiStore.Add(sbiToAdd)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Delete deletes a sbi from the sbi store.
+func (s *SbiService) Delete(sbiToDelete southbound.SouthboundInterface) error {
+	err := s.sbiStore.Delete(sbiToDelete)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (s *SbiService) createSbiFromStore(loadedSbi southbound.LoadedSbi) (southbound.SouthboundInterface, error) {
+	newSbi, err := NewSBI(loadedSbi.Type, uuid.MustParse(loadedSbi.ID))
+	if err != nil {
+		return nil, err
+	}
+
+	return newSbi, nil
+}
diff --git a/controller/nucleus/sbiService_test.go b/controller/nucleus/sbiService_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..d26d6d72e1096326926d1033594645e14f09f603
--- /dev/null
+++ b/controller/nucleus/sbiService_test.go
@@ -0,0 +1,95 @@
+package nucleus
+
+import (
+	"testing"
+
+	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound"
+	"code.fbi.h-da.de/danet/gosdn/controller/store"
+	"github.com/google/uuid"
+)
+
+func getMockSbi(sbiID uuid.UUID) southbound.SouthboundInterface {
+	return &OpenConfig{id: sbiID}
+}
+
+func getSbiTestStores(t *testing.T, sbiID uuid.UUID) (southbound.Service, southbound.SouthboundInterface) {
+	sbiStore := NewMemorySbiStore()
+	sbiService := NewSbiService(sbiStore)
+
+	mockSbi := getMockSbi(sbiID)
+
+	err := sbiService.Add(mockSbi)
+	if err != nil {
+		t.Error("could not create sbi")
+	}
+
+	return sbiService, mockSbi
+}
+
+func TestSbiService_Get(t *testing.T) {
+	sbiID := uuid.New()
+
+	sbiService, mockSbi := getSbiTestStores(t, sbiID)
+
+	sbi, err := sbiService.Get(store.Query{
+		ID:   mockSbi.ID(),
+		Name: mockSbi.Name(),
+	})
+	if err != nil {
+		t.Error("could not get sbi")
+	}
+
+	if mockSbi.ID() != sbi.ID() {
+		t.Errorf("Expected ID=%s, got %s", mockSbi.ID(), sbi.ID())
+	}
+}
+
+func TestSbiService_Delete(t *testing.T) {
+	sbiID := uuid.New()
+
+	sbiService, mockSbi := getSbiTestStores(t, sbiID)
+
+	sbi, err := sbiService.Get(store.Query{
+		ID:   mockSbi.ID(),
+		Name: mockSbi.Name(),
+	})
+	if err != nil {
+		t.Error("could not get sbi")
+	}
+
+	err = sbiService.Delete(sbi)
+	if err != nil {
+		t.Error("could not delete sbi")
+	}
+}
+
+func TestSbiService_GetAll(t *testing.T) {
+	sbiID := uuid.New()
+	sbiID2 := uuid.New()
+
+	sbiService, mockSbi := getSbiTestStores(t, sbiID)
+
+	_, err := sbiService.Get(store.Query{
+		ID:   mockSbi.ID(),
+		Name: mockSbi.Name(),
+	})
+	if err != nil {
+		t.Error("could not get sbi")
+	}
+
+	mockSbi2 := getMockSbi(sbiID2)
+
+	err = sbiService.Add(mockSbi2)
+	if err != nil {
+		t.Error("could not add sbi")
+	}
+
+	sbis, err := sbiService.GetAll()
+	if err != nil {
+		t.Error("could not get all devices")
+	}
+
+	if len(sbis) != 2 {
+		t.Errorf("Expected len(devices)=2, got %d", len(sbis))
+	}
+}
diff --git a/controller/nucleus/sbiStore.go b/controller/nucleus/sbiStore.go
index 16fdb7bbe971fb2a18b7ea18e1fd9f3fb307f042..7038980cfb26fec86fa0c4d348544f3eb25df509 100644
--- a/controller/nucleus/sbiStore.go
+++ b/controller/nucleus/sbiStore.go
@@ -3,7 +3,6 @@ package nucleus
 import (
 	"fmt"
 
-	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/store"
 
@@ -19,31 +18,23 @@ type SbiStore struct {
 	sbiStoreName string
 }
 
-// LoadedSbi represents a Southbound Interface that was loaded by using
-// the Load() method of the SbiStore.
-type LoadedSbi struct {
-	ID   string   `json:"_id" bson:"_id,omitempty"`
-	Type spb.Type `bson:"type"`
-	Path string   `json:"path,omitempty"`
-}
-
 // NewSbiStore returns a sbiStore
-func NewSbiStore(pndUUID uuid.UUID) southbound.SbiStore {
+func NewSbiStore(pndUUID uuid.UUID) southbound.Store {
 	storeMode := store.GetStoreMode()
 
 	switch storeMode {
 	case store.Filesystem:
-		store := NewGenericStore[southbound.SouthboundInterface]()
+		store := NewMemorySbiStore()
 
-		return &store
+		return store
 	case store.Database:
 		return &DatabaseSbiStore{
 			sbiStoreName: fmt.Sprintf("sbi-store-%s.json", pndUUID.String()),
 		}
 	case store.Memory:
-		store := NewGenericStore[southbound.SouthboundInterface]()
+		store := NewMemorySbiStore()
 
-		return &store
+		return store
 	default:
 		return nil
 	}
diff --git a/controller/nucleus/southbound.go b/controller/nucleus/southbound.go
index 2c18dd0922a9ed401f16782e2c4a7715eb3bbe60..927900849076da638a2623a8a5da4ca1123841ff 100644
--- a/controller/nucleus/southbound.go
+++ b/controller/nucleus/southbound.go
@@ -1,6 +1,7 @@
 package nucleus
 
 import (
+	"encoding/json"
 	"path/filepath"
 
 	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors"
@@ -294,7 +295,29 @@ func (p *SouthboundPlugin) Update() error {
 	return nil
 }
 
-// MarshalBSON implements the MarshalBSON interface to store a device as BSON
+// MarshalJSON implements the MarshalJSON interface to store a sbi as JSON
+func (p *SouthboundPlugin) MarshalJSON() ([]byte, error) {
+	return json.Marshal(&struct {
+		ID   string   `json:"_id"`
+		Type spb.Type `json:"type"`
+	}{
+		ID:   p.sbi.ID().String(),
+		Type: p.Type(),
+	})
+}
+
+// MarshalJSON implements the MarshalJSON interface to store a sbi as JSON
+func (oc *OpenConfig) MarshalJSON() ([]byte, error) {
+	return json.Marshal(&struct {
+		ID   string   `json:"_id"`
+		Type spb.Type `json:"type"`
+	}{
+		ID:   oc.id.String(),
+		Type: oc.Type(),
+	})
+}
+
+// MarshalBSON implements the MarshalBSON interface to store a sbi as BSON
 func (p *SouthboundPlugin) MarshalBSON() ([]byte, error) {
 	return bson.Marshal(&struct {
 		ID   string   `bson:"_id"`
@@ -305,7 +328,7 @@ func (p *SouthboundPlugin) MarshalBSON() ([]byte, error) {
 	})
 }
 
-// MarshalBSON implements the MarshalBSON interface to store a device as BSON
+// MarshalBSON implements the MarshalBSON interface to store a sbi as BSON
 func (oc *OpenConfig) MarshalBSON() ([]byte, error) {
 	return bson.Marshal(&struct {
 		ID   string   `bson:"_id"`