diff --git a/examples/example01/Dockerfile.debug b/examples/example01/Dockerfile.debug
index 4b322e91938bd3b86d6dbd2600c9b536f0ec6dc7..2de98b9b4e38ee9f00ed6e1bb2e56a78663e50a4 100644
--- a/examples/example01/Dockerfile.debug
+++ b/examples/example01/Dockerfile.debug
@@ -1,4 +1,4 @@
-ARG GOLANG_VERSION=1.20.3
+ARG GOLANG_VERSION=1.22
 ARG BUILDARGS
 
 FROM golang:$GOLANG_VERSION-buster as builder
@@ -6,7 +6,7 @@ WORKDIR /gnmi-target/
 COPY . .
 RUN --mount=type=cache,target=/root/go/pkg/mod \
     --mount=type=cache,target=/root/.cache/go-build
-RUN go install github.com/go-delve/delve/cmd/dlv@v1.20.2
+RUN go install github.com/go-delve/delve/cmd/dlv@v1.22.1
 RUN make build-debug
 
 FROM ubuntu:22.04 as ubuntu
diff --git a/examples/example01/cmd/start.go b/examples/example01/cmd/start.go
index 9edb84f65afd1b189d35e43c438fdf2b6547e46b..88d5f00f8ca2b578636044f152abeff62cd67855 100644
--- a/examples/example01/cmd/start.go
+++ b/examples/example01/cmd/start.go
@@ -37,6 +37,7 @@ import (
 	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/handlers/interfaces"
 	networkinstances "code.fbi.h-da.de/danet/gnmi-target/examples/example01/handlers/network-instances"
 	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/handlers/system"
+
 	gnmitargetygot "code.fbi.h-da.de/danet/gnmi-target/examples/example01/model"
 	"code.fbi.h-da.de/danet/gnmi-target/handler"
 	"github.com/sirupsen/logrus"
diff --git a/examples/example01/handlers/interfaces/interfacesHandler.go b/examples/example01/handlers/interfaces/interfacesHandler.go
index fd5d8a67be5e4c76fcfe311d03b3a066ffc9e7f0..155b558dd71d7629a86e7286522adad9134f5aa7 100644
--- a/examples/example01/handlers/interfaces/interfacesHandler.go
+++ b/examples/example01/handlers/interfaces/interfacesHandler.go
@@ -7,6 +7,7 @@ import (
 	gnmitargetygot "code.fbi.h-da.de/danet/gnmi-target/examples/example01/model"
 	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/osclient"
 	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/osclient/additions"
+	"code.fbi.h-da.de/danet/gnmi-target/handler"
 	"github.com/openconfig/gnmi/proto/gnmi"
 	"github.com/openconfig/ygot/ygot"
 	log "github.com/sirupsen/logrus"
@@ -14,34 +15,25 @@ import (
 
 // InterfacesHandler is the implementation of a gnmitarget.PathHandler.
 type InterfacesHandler struct {
-	name     string
-	paths    map[string]struct{}
+	handler.DefaultPathHandler
 	osClient osclient.Osclient
 }
 
 func NewInterfacesHandler() *InterfacesHandler {
 	return &InterfacesHandler{
-		name: "openconfig-interfaces-handler",
-		paths: map[string]struct{}{
-			"/interfaces": struct{}{},
+		DefaultPathHandler: handler.DefaultPathHandler{
+			Name: "openconfig-interfaces-handler",
+			Paths: map[string]struct{}{
+				"/interfaces": {},
+			},
 		},
 		osClient: osclient.NewOsClient(),
 	}
 }
 
-func (yh *InterfacesHandler) Name() string {
-	return yh.name
-}
-
-func (yh *InterfacesHandler) Paths() map[string]struct{} {
-	return yh.paths
-}
-
-func (yh *InterfacesHandler) Init(c ygot.ValidatedGoStruct) error {
-	config, ok := c.(*gnmitargetygot.Gnmitarget)
-	if !ok {
-		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
-	}
+func (yh *InterfacesHandler) Init(config *handler.Config, publishToSubsFunc func([]*gnmi.Notification) error) error {
+	yh.Config = config
+	yh.PublishToSubs = publishToSubsFunc
 
 	// needed for interfaces and network instances
 	localInterfaces, err := yh.osClient.GetInterfaces()
@@ -49,10 +41,9 @@ func (yh *InterfacesHandler) Init(c ygot.ValidatedGoStruct) error {
 		return err
 	}
 
-	confInterfaces := config.GetOrCreateInterfaces()
-
 	for _, localInterface := range localInterfaces {
-		if err := updateOrCreateInterface(confInterfaces, localInterface); err != nil {
+		_, err := yh.updateOrCreateInterface(localInterface)
+		if err != nil {
 			return err
 		}
 	}
@@ -66,8 +57,15 @@ func (yh *InterfacesHandler) Init(c ygot.ValidatedGoStruct) error {
 		for {
 			select {
 			case update := <-interfaceChannel:
-				if err := updateOrCreateInterface(confInterfaces, update); err != nil {
-					fmt.Println("Error within interface subscription goroutine.")
+				//lock access for model
+				diff, err := yh.updateOrCreateInterface(update)
+				if err != nil {
+					log.Errorf("Error within interface subscription goroutine; %v", err)
+					// TODO: check again
+					break
+				}
+				if err := yh.PublishToSubs(diff); err != nil {
+					log.Errorf("Error within interface subscription goroutine; %v", err)
 				}
 			}
 		}
@@ -77,7 +75,7 @@ func (yh *InterfacesHandler) Init(c ygot.ValidatedGoStruct) error {
 }
 
 func (yh *InterfacesHandler) Update(c ygot.ValidatedGoStruct, updates []*gnmi.Update) error {
-	fmt.Println("Update request received for ", yh.name)
+	fmt.Println("Update request received for ", yh.GetName())
 	config, ok := c.(*gnmitargetygot.Gnmitarget)
 	if !ok {
 		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
@@ -149,7 +147,22 @@ func (yh *InterfacesHandler) Update(c ygot.ValidatedGoStruct, updates []*gnmi.Up
 	return nil
 }
 
-func updateOrCreateInterface(confInterfaces *gnmitargetygot.OpenconfigInterfaces_Interfaces, localInterface *additions.Interface) error {
+func (yh *InterfacesHandler) updateOrCreateInterface(localInterface *additions.Interface) ([]*gnmi.Notification, error) {
+	yh.Config.Lock()
+	defer yh.Config.Unlock()
+
+	copyCurrentConfig, err := ygot.DeepCopy(yh.Config.Data)
+	if err != nil {
+		return nil, err
+	}
+
+	newConfig, ok := copyCurrentConfig.(*gnmitargetygot.Gnmitarget)
+	if !ok {
+		return nil, fmt.Errorf("Wrong type, exptected: %T, got: %T", (*gnmitargetygot.OpenconfigInterfaces_Interfaces)(nil), copyCurrentConfig)
+	}
+
+	confInterfaces := newConfig.GetOrCreateInterfaces()
+
 	iface := confInterfaces.GetOrCreateInterface(*localInterface.Name)
 	state := iface.GetOrCreateState()
 	config := iface.GetOrCreateConfig()
@@ -198,9 +211,16 @@ func updateOrCreateInterface(confInterfaces *gnmitargetygot.OpenconfigInterfaces
 	}
 
 	//validate struct
-	if err := confInterfaces.Validate(); err != nil {
-		return err
+	if err := newConfig.Validate(); err != nil {
+		return nil, err
 	}
 
-	return nil
+	notifications, err := ygot.DiffWithAtomic(yh.Config.Data, newConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	yh.Config.Data = newConfig
+
+	return notifications, nil
 }
diff --git a/examples/example01/handlers/network-instances/networkInstanceHandler.go b/examples/example01/handlers/network-instances/networkInstanceHandler.go
index b27599a43d83f93943800e144bed29039fafcd48..b37b5eaddf25304d70e34042cb56346bba622c93 100644
--- a/examples/example01/handlers/network-instances/networkInstanceHandler.go
+++ b/examples/example01/handlers/network-instances/networkInstanceHandler.go
@@ -6,6 +6,7 @@ import (
 	gnmitargetygot "code.fbi.h-da.de/danet/gnmi-target/examples/example01/model"
 	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/osclient"
 	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/osclient/additions"
+	"code.fbi.h-da.de/danet/gnmi-target/handler"
 	"github.com/openconfig/gnmi/proto/gnmi"
 	"github.com/openconfig/ygot/ygot"
 	log "github.com/sirupsen/logrus"
@@ -13,34 +14,25 @@ import (
 
 // NetworkInstanceHandler is the implementation of a gnmitarget.PathHandler.
 type NetworkInstanceHandler struct {
-	name     string
-	paths    map[string]struct{}
+	handler.DefaultPathHandler
 	osClient osclient.Osclient
 }
 
 func NewNetworkInstanceHandler() *NetworkInstanceHandler {
 	return &NetworkInstanceHandler{
-		name: "openconfig-network-instance-handler",
-		paths: map[string]struct{}{
-			"/network-instances": struct{}{},
+		DefaultPathHandler: handler.DefaultPathHandler{
+			Name: "openconfig-network-instance-handler",
+			Paths: map[string]struct{}{
+				"/network-instances": {},
+			},
 		},
 		osClient: osclient.NewOsClient(),
 	}
 }
 
-func (yh *NetworkInstanceHandler) Name() string {
-	return yh.name
-}
-
-func (yh *NetworkInstanceHandler) Paths() map[string]struct{} {
-	return yh.paths
-}
-
-func (yh *NetworkInstanceHandler) Init(c ygot.ValidatedGoStruct) error {
-	config, ok := c.(*gnmitargetygot.Gnmitarget)
-	if !ok {
-		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
-	}
+func (yh *NetworkInstanceHandler) Init(config *handler.Config, publishToSubsFunc func([]*gnmi.Notification) error) error {
+	yh.Config = config
+	yh.PublishToSubs = publishToSubsFunc
 
 	// needed for interfaces and network instances
 	localInterfaces, err := yh.osClient.GetInterfaces()
@@ -48,8 +40,6 @@ func (yh *NetworkInstanceHandler) Init(c ygot.ValidatedGoStruct) error {
 		return err
 	}
 
-	confNetworkInstances := config.GetOrCreateNetworkInstances()
-
 	for _, localInterface := range localInterfaces {
 		staticRoutes, err := yh.osClient.GetStaticRoutes(*localInterface.Name)
 		if err != nil {
@@ -57,7 +47,8 @@ func (yh *NetworkInstanceHandler) Init(c ygot.ValidatedGoStruct) error {
 		}
 
 		for _, staticRoute := range staticRoutes {
-			if err := updateOrCreateNetworkInstance(confNetworkInstances, staticRoute); err != nil {
+			_, err := yh.updateOrCreateNetworkInstance(staticRoute)
+			if err != nil {
 				return err
 			}
 		}
@@ -67,7 +58,7 @@ func (yh *NetworkInstanceHandler) Init(c ygot.ValidatedGoStruct) error {
 }
 
 func (yh *NetworkInstanceHandler) Update(c ygot.ValidatedGoStruct, jobs []*gnmi.Update) error {
-	fmt.Println("Update request received for ", yh.name)
+	fmt.Println("Update request received for ", yh.Name)
 	config, ok := c.(*gnmitargetygot.Gnmitarget)
 	if !ok {
 		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
@@ -111,8 +102,26 @@ func (yh *NetworkInstanceHandler) Update(c ygot.ValidatedGoStruct, jobs []*gnmi.
 	return nil
 }
 
-func updateOrCreateNetworkInstance(confNetworkInstances *gnmitargetygot.OpenconfigNetworkInstance_NetworkInstances, localStaticRoute *additions.StaticRoute) error {
+func (yh *NetworkInstanceHandler) updateOrCreateNetworkInstance(localStaticRoute *additions.StaticRoute) ([]*gnmi.Notification, error) {
+	yh.Config.Lock()
+	defer yh.Config.Unlock()
+
+	copyCurrentConfig, err := ygot.DeepCopy(yh.Config.Data)
+	if err != nil {
+		return nil, err
+	}
+
+	newConfig, ok := copyCurrentConfig.(*gnmitargetygot.Gnmitarget)
+	if !ok {
+		return nil, fmt.Errorf("Wrong type, exptected: %T, got: %T", (*gnmitargetygot.OpenconfigInterfaces_Interfaces)(nil), copyCurrentConfig)
+	}
+
+	confNetworkInstances := newConfig.GetOrCreateNetworkInstances()
+
 	if networkInstances := confNetworkInstances.GetOrCreateNetworkInstance("DEFAULT"); networkInstances != nil && localStaticRoute != nil {
+		if config := networkInstances.GetOrCreateConfig(); config != nil {
+			config.Name = ygot.String("DEFAULT")
+		}
 		if protocols := networkInstances.GetOrCreateProtocols(); protocols != nil {
 			staticProtocol := protocols.GetOrCreateProtocol(gnmitargetygot.OpenconfigPolicyTypes_INSTALL_PROTOCOL_TYPE_STATIC, "STATIC")
 
@@ -145,5 +154,18 @@ func updateOrCreateNetworkInstance(confNetworkInstances *gnmitargetygot.Openconf
 			}
 		}
 	}
-	return nil
+
+	//validate struct
+	if err := newConfig.Validate(); err != nil {
+		return nil, err
+	}
+
+	notifications, err := ygot.DiffWithAtomic(yh.Config.Data, newConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	yh.Config.Data = newConfig
+
+	return notifications, nil
 }
diff --git a/examples/example01/handlers/system/hostnameHandler.go b/examples/example01/handlers/system/hostnameHandler.go
index 9ca31617948f3aed87fd876ef2f03d09cdc73b56..00deb0b364db120ad596d15ebf70725f94081587 100644
--- a/examples/example01/handlers/system/hostnameHandler.go
+++ b/examples/example01/handlers/system/hostnameHandler.go
@@ -5,6 +5,7 @@ import (
 
 	gnmitargetygot "code.fbi.h-da.de/danet/gnmi-target/examples/example01/model"
 	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/osclient"
+	"code.fbi.h-da.de/danet/gnmi-target/handler"
 	"github.com/openconfig/gnmi/proto/gnmi"
 	"github.com/openconfig/ygot/ygot"
 	"github.com/sirupsen/logrus"
@@ -12,45 +13,36 @@ import (
 
 // HostnameHandler is the implementation of a gnmitarget.PathHandler.
 type HostnameHandler struct {
-	name     string
-	paths    map[string]struct{}
+	handler.DefaultPathHandler
 	osClient osclient.Osclient
 	weight   int
 }
 
 func NewHostnameHandler() *HostnameHandler {
 	return &HostnameHandler{
-		name: "openconfig-hostname-handler",
-		paths: map[string]struct{}{
-			"/system/config/hostname": struct{}{},
+		DefaultPathHandler: handler.DefaultPathHandler{
+			Name: "openconfig-hostname-handler",
+			Paths: map[string]struct{}{
+				"/system/config/hostname": {},
+			},
 		},
 		osClient: osclient.NewOsClient(),
 	}
 }
 
-func (yh *HostnameHandler) Name() string {
-	return yh.name
-}
-
-func (yh *HostnameHandler) Paths() map[string]struct{} {
-	return yh.paths
-}
-
-func (yh *HostnameHandler) Init(c ygot.ValidatedGoStruct) error {
-	config, ok := c.(*gnmitargetygot.Gnmitarget)
-	if !ok {
-		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
-	}
+func (yh *HostnameHandler) Init(config *handler.Config, publishToSubsFunc func([]*gnmi.Notification) error) error {
+	yh.Config = config
+	yh.PublishToSubs = publishToSubsFunc
 
-	confSystem := config.GetOrCreateSystem()
-	if err := updateOrCreateHostname(confSystem, yh.osClient); err != nil {
+	_, err := yh.updateOrCreateHostname(yh.osClient)
+	if err != nil {
 		return err
 	}
 	return nil
 }
 
 func (yh *HostnameHandler) Update(c ygot.ValidatedGoStruct, jobs []*gnmi.Update) error {
-	fmt.Println("Update request received for ", yh.name)
+	fmt.Println("Update request received for ", yh.Name)
 	config, ok := c.(*gnmitargetygot.Gnmitarget)
 	if !ok {
 		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
@@ -72,19 +64,41 @@ func (yh *HostnameHandler) Update(c ygot.ValidatedGoStruct, jobs []*gnmi.Update)
 	return nil
 }
 
-func updateOrCreateHostname(confSystem *gnmitargetygot.OpenconfigSystem_System, os osclient.Osclient) error {
+func (yh *HostnameHandler) updateOrCreateHostname(os osclient.Osclient) ([]*gnmi.Notification, error) {
+	yh.Config.Lock()
+	defer yh.Config.Unlock()
+
+	copyCurrentConfig, err := ygot.DeepCopy(yh.Config.Data)
+	if err != nil {
+		return nil, err
+	}
+
+	newConfig, ok := copyCurrentConfig.(*gnmitargetygot.Gnmitarget)
+	if !ok {
+		return nil, fmt.Errorf("Wrong type, exptected: %T, got: %T", (*gnmitargetygot.OpenconfigInterfaces_Interfaces)(nil), copyCurrentConfig)
+	}
+
+	confSystem := newConfig.GetOrCreateSystem()
+
 	if config := confSystem.GetOrCreateConfig(); config != nil {
 		h, err := os.GetHostname()
 		if err != nil {
-			return err
+			return nil, err
 		}
 		config.Hostname = &h
 	}
 
 	//validate struct
-	if err := confSystem.Validate(); err != nil {
-		return err
+	if err := newConfig.Validate(); err != nil {
+		return nil, err
 	}
 
-	return nil
+	notifications, err := ygot.DiffWithAtomic(yh.Config.Data, newConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	yh.Config.Data = newConfig
+
+	return notifications, nil
 }
diff --git a/examples/example01/handlers/system/memoryHandler.go b/examples/example01/handlers/system/memoryHandler.go
index b99115a0946c10fab9088f78758c59f5d590aec0..dfd9873698df8fc71c26be974ef9fc1d2469ef74 100644
--- a/examples/example01/handlers/system/memoryHandler.go
+++ b/examples/example01/handlers/system/memoryHandler.go
@@ -5,54 +5,61 @@ import (
 
 	gnmitargetygot "code.fbi.h-da.de/danet/gnmi-target/examples/example01/model"
 	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/osclient"
+	"code.fbi.h-da.de/danet/gnmi-target/handler"
 	"github.com/openconfig/gnmi/proto/gnmi"
 	"github.com/openconfig/ygot/ygot"
 )
 
 // MemoryHandler is the implementation of a gnmitarget.PathHandler.
 type MemoryHandler struct {
-	name     string
-	paths    map[string]struct{}
+	handler.DefaultPathHandler
 	osClient osclient.Osclient
 }
 
 func NewMemoryHandler() *MemoryHandler {
 	return &MemoryHandler{
-		name: "openconfig-memory-handler",
-		paths: map[string]struct{}{
-			"/system/memory/state": struct{}{},
+		DefaultPathHandler: handler.DefaultPathHandler{
+			Name: "openconfig-memory-handler",
+			Paths: map[string]struct{}{
+				"/system/memory/state": {},
+			},
 		},
 		osClient: osclient.NewOsClient(),
 	}
 }
 
-func (yh *MemoryHandler) Name() string {
-	return yh.name
-}
-
-func (yh *MemoryHandler) Paths() map[string]struct{} {
-	return yh.paths
-}
+func (yh *MemoryHandler) Init(config *handler.Config, publishToSubsFunc func([]*gnmi.Notification) error) error {
+	yh.Config = config
+	yh.PublishToSubs = publishToSubsFunc
 
-func (yh *MemoryHandler) Init(c ygot.ValidatedGoStruct) error {
-	config, ok := c.(*gnmitargetygot.Gnmitarget)
-	if !ok {
-		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
-	}
-
-	confSystem := config.GetOrCreateSystem()
-	if err := updateOrCreateMemory(confSystem, yh.osClient); err != nil {
+	_, err := yh.updateOrCreateMemory(yh.osClient)
+	if err != nil {
 		return err
 	}
 	return nil
 }
 
 func (yh *MemoryHandler) Update(c ygot.ValidatedGoStruct, jobs []*gnmi.Update) error {
-	fmt.Println("Update request received for ", yh.name)
+	fmt.Println("Update request received for ", yh.Name)
 	return nil
 }
 
-func updateOrCreateMemory(confSystem *gnmitargetygot.OpenconfigSystem_System, os osclient.Osclient) error {
+func (yh *MemoryHandler) updateOrCreateMemory(os osclient.Osclient) ([]*gnmi.Notification, error) {
+	yh.Config.Lock()
+	defer yh.Config.Unlock()
+
+	copyCurrentConfig, err := ygot.DeepCopy(yh.Config.Data)
+	if err != nil {
+		return nil, err
+	}
+
+	newConfig, ok := copyCurrentConfig.(*gnmitargetygot.Gnmitarget)
+	if !ok {
+		return nil, fmt.Errorf("Wrong type, exptected: %T, got: %T", (*gnmitargetygot.OpenconfigInterfaces_Interfaces)(nil), copyCurrentConfig)
+	}
+
+	confSystem := newConfig.GetOrCreateSystem()
+
 	if memory := confSystem.GetOrCreateMemory(); memory != nil {
 		memory.GetOrCreateState().Physical = ygot.Uint64(os.GetTotalMemory())
 		memory.GetOrCreateState().Free = ygot.Uint64(os.GetFreeMemory())
@@ -60,9 +67,16 @@ func updateOrCreateMemory(confSystem *gnmitargetygot.OpenconfigSystem_System, os
 	}
 
 	//validate struct
-	if err := confSystem.Validate(); err != nil {
-		return err
+	if err := newConfig.Validate(); err != nil {
+		return nil, err
 	}
 
-	return nil
+	notifications, err := ygot.DiffWithAtomic(yh.Config.Data, newConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	yh.Config.Data = newConfig
+
+	return notifications, nil
 }
diff --git a/examples/example01/handlers/system/motdHandler.go b/examples/example01/handlers/system/motdHandler.go
index a9ebcd9fe304efd1681bff2384578e2a7fe6d3c3..19964a2dd33125303c1899783d566d817b24441a 100644
--- a/examples/example01/handlers/system/motdHandler.go
+++ b/examples/example01/handlers/system/motdHandler.go
@@ -5,6 +5,7 @@ import (
 
 	gnmitargetygot "code.fbi.h-da.de/danet/gnmi-target/examples/example01/model"
 	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/osclient"
+	"code.fbi.h-da.de/danet/gnmi-target/handler"
 	"github.com/openconfig/gnmi/proto/gnmi"
 	"github.com/openconfig/ygot/ygot"
 	"github.com/sirupsen/logrus"
@@ -12,44 +13,35 @@ import (
 
 // MotdHandler is the implementation of a gnmitarget.PathHandler.
 type MotdHandler struct {
-	name     string
-	paths    map[string]struct{}
+	handler.DefaultPathHandler
 	osClient osclient.Osclient
 }
 
 func NewMotdHandler() *MotdHandler {
 	return &MotdHandler{
-		name: "openconfig-motd-handler",
-		paths: map[string]struct{}{
-			"/system/config/motd-banner": struct{}{},
+		DefaultPathHandler: handler.DefaultPathHandler{
+			Name: "openconfig-motd-handler",
+			Paths: map[string]struct{}{
+				"/system/config/motd-banner": {},
+			},
 		},
 		osClient: osclient.NewOsClient(),
 	}
 }
 
-func (yh *MotdHandler) Name() string {
-	return yh.name
-}
-
-func (yh *MotdHandler) Paths() map[string]struct{} {
-	return yh.paths
-}
-
-func (yh *MotdHandler) Init(c ygot.ValidatedGoStruct) error {
-	config, ok := c.(*gnmitargetygot.Gnmitarget)
-	if !ok {
-		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
-	}
+func (yh *MotdHandler) Init(config *handler.Config, publishToSubsFunc func([]*gnmi.Notification) error) error {
+	yh.Config = config
+	yh.PublishToSubs = publishToSubsFunc
 
-	confSystem := config.GetOrCreateSystem()
-	if err := updateOrCreateMotd(confSystem, yh.osClient); err != nil {
+	_, err := yh.updateOrCreateMotd(yh.osClient)
+	if err != nil {
 		return err
 	}
 	return nil
 }
 
 func (yh *MotdHandler) Update(c ygot.ValidatedGoStruct, jobs []*gnmi.Update) error {
-	fmt.Println("Update request received for ", yh.name)
+	fmt.Println("Update request received for ", yh.Name)
 	config, ok := c.(*gnmitargetygot.Gnmitarget)
 	if !ok {
 		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
@@ -71,19 +63,40 @@ func (yh *MotdHandler) Update(c ygot.ValidatedGoStruct, jobs []*gnmi.Update) err
 	return nil
 }
 
-func updateOrCreateMotd(confSystem *gnmitargetygot.OpenconfigSystem_System, os osclient.Osclient) error {
+func (yh *MotdHandler) updateOrCreateMotd(os osclient.Osclient) ([]*gnmi.Notification, error) {
+	yh.Config.Lock()
+	defer yh.Config.Unlock()
+
+	copyCurrentConfig, err := ygot.DeepCopy(yh.Config.Data)
+	if err != nil {
+		return nil, err
+	}
+
+	newConfig, ok := copyCurrentConfig.(*gnmitargetygot.Gnmitarget)
+	if !ok {
+		return nil, fmt.Errorf("Wrong type, exptected: %T, got: %T", (*gnmitargetygot.OpenconfigInterfaces_Interfaces)(nil), copyCurrentConfig)
+	}
+
+	confSystem := newConfig.GetOrCreateSystem()
 	if config := confSystem.GetOrCreateConfig(); config != nil {
 		motd, err := os.GetMotd()
 		if err != nil {
-			return err
+			return nil, err
 		}
 		config.MotdBanner = ygot.String(motd)
 	}
 
 	//validate struct
-	if err := confSystem.Validate(); err != nil {
-		return err
+	if err := newConfig.Validate(); err != nil {
+		return nil, err
 	}
 
-	return nil
+	notifications, err := ygot.DiffWithAtomic(yh.Config.Data, newConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	yh.Config.Data = newConfig
+
+	return notifications, nil
 }
diff --git a/examples/example01/handlers/system/stateHandler.go b/examples/example01/handlers/system/stateHandler.go
index 46f6f9cf2ba738906341eae2fa5474bfa84abade..bd43316efc5986c508526eeda1aaae1b1d6313e6 100644
--- a/examples/example01/handlers/system/stateHandler.go
+++ b/examples/example01/handlers/system/stateHandler.go
@@ -6,6 +6,7 @@ import (
 
 	gnmitargetygot "code.fbi.h-da.de/danet/gnmi-target/examples/example01/model"
 	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/osclient"
+	"code.fbi.h-da.de/danet/gnmi-target/handler"
 	"github.com/openconfig/gnmi/proto/gnmi"
 	"github.com/openconfig/ygot/ygot"
 	gopshost "github.com/shirou/gopsutil/host"
@@ -13,53 +14,59 @@ import (
 
 // StateHandler is the implementation of a gnmitarget.PathHandler.
 type StateHandler struct {
-	name     string
-	paths    map[string]struct{}
+	handler.DefaultPathHandler
 	osClient osclient.Osclient
 }
 
 func NewStateHandler() *StateHandler {
 	return &StateHandler{
-		name: "openconfig-memory-handler",
-		paths: map[string]struct{}{
-			"/system/state": struct{}{},
+		DefaultPathHandler: handler.DefaultPathHandler{
+			Name: "openconfig-memory-handler",
+			Paths: map[string]struct{}{
+				"/system/state": {},
+			},
 		},
 		osClient: osclient.NewOsClient(),
 	}
 }
 
-func (yh *StateHandler) Name() string {
-	return yh.name
-}
-
-func (yh *StateHandler) Paths() map[string]struct{} {
-	return yh.paths
-}
+func (yh *StateHandler) Init(config *handler.Config, publishToSubsFunc func([]*gnmi.Notification) error) error {
+	yh.Config = config
+	yh.PublishToSubs = publishToSubsFunc
 
-func (yh *StateHandler) Init(c ygot.ValidatedGoStruct) error {
-	config, ok := c.(*gnmitargetygot.Gnmitarget)
-	if !ok {
-		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
-	}
-
-	confSystem := config.GetOrCreateSystem()
-	if err := updateOrCreateState(confSystem, yh.osClient); err != nil {
+	_, err := yh.updateOrCreateState(yh.osClient)
+	if err != nil {
 		return err
 	}
 	return nil
 }
 
 func (yh *StateHandler) Update(c ygot.ValidatedGoStruct, jobs []*gnmi.Update) error {
-	fmt.Println("Update request received for ", yh.name)
+	fmt.Println("Update request received for ", yh.Name)
 	return nil
 }
 
-func updateOrCreateState(confSystem *gnmitargetygot.OpenconfigSystem_System, os osclient.Osclient) error {
+func (yh *StateHandler) updateOrCreateState(os osclient.Osclient) ([]*gnmi.Notification, error) {
+	yh.Config.Lock()
+	defer yh.Config.Unlock()
+
+	copyCurrentConfig, err := ygot.DeepCopy(yh.Config.Data)
+	if err != nil {
+		return nil, err
+	}
+
+	newConfig, ok := copyCurrentConfig.(*gnmitargetygot.Gnmitarget)
+	if !ok {
+		return nil, fmt.Errorf("Wrong type, exptected: %T, got: %T", (*gnmitargetygot.OpenconfigInterfaces_Interfaces)(nil), copyCurrentConfig)
+	}
+
+	confSystem := newConfig.GetOrCreateSystem()
+
 	if state := confSystem.GetOrCreateState(); state != nil {
 		state.CurrentDatetime = ygot.String(time.Now().Format(time.RFC3339))
 		bootTime, err := gopshost.BootTime()
 		if err != nil {
-			return err
+			return nil, err
 		}
 		state.BootTime = ygot.Uint64(bootTime)
 
@@ -70,9 +77,16 @@ func updateOrCreateState(confSystem *gnmitargetygot.OpenconfigSystem_System, os
 	}
 
 	//validate struct
-	if err := confSystem.Validate(); err != nil {
-		return err
+	if err := newConfig.Validate(); err != nil {
+		return nil, err
 	}
 
-	return nil
+	notifications, err := ygot.DiffWithAtomic(yh.Config.Data, newConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	yh.Config.Data = newConfig
+
+	return notifications, nil
 }
diff --git a/examples/example01/handlers/system/systemHandler.go b/examples/example01/handlers/system/systemHandler.go
index 5609ffcdc1951f2845de32443d795bf1bb07cb04..3a32b24947a1333bdcb4a88a2b86e31676d70241 100644
--- a/examples/example01/handlers/system/systemHandler.go
+++ b/examples/example01/handlers/system/systemHandler.go
@@ -6,58 +6,65 @@ import (
 
 	gnmitargetygot "code.fbi.h-da.de/danet/gnmi-target/examples/example01/model"
 	"code.fbi.h-da.de/danet/gnmi-target/examples/example01/osclient"
+	"code.fbi.h-da.de/danet/gnmi-target/handler"
 	"github.com/openconfig/gnmi/proto/gnmi"
 	"github.com/openconfig/ygot/ygot"
 )
 
 // SystemHandler is the implementation of a gnmitarget.PathHandler.
 type SystemHandler struct {
-	name     string
-	paths    map[string]struct{}
+	handler.DefaultPathHandler
 	osClient osclient.Osclient
 }
 
 func NewSystemHandler() *SystemHandler {
 	return &SystemHandler{
-		name: "openconfig-system-handler",
-		paths: map[string]struct{}{
-			"/system": struct{}{},
+		DefaultPathHandler: handler.DefaultPathHandler{
+			Name: "openconfig-system-handler",
+			Paths: map[string]struct{}{
+				"/system": {},
+			},
 		},
 		osClient: osclient.NewOsClient(),
 	}
 }
 
-func (yh *SystemHandler) Name() string {
-	return yh.name
-}
-
-func (yh *SystemHandler) Paths() map[string]struct{} {
-	return yh.paths
-}
+func (yh *SystemHandler) Init(config *handler.Config, publishToSubsFunc func([]*gnmi.Notification) error) error {
+	yh.Config = config
+	yh.PublishToSubs = publishToSubsFunc
 
-func (yh *SystemHandler) Init(c ygot.ValidatedGoStruct) error {
-	config, ok := c.(*gnmitargetygot.Gnmitarget)
-	if !ok {
-		return fmt.Errorf("failed type assertion for config %T", (*gnmitargetygot.Gnmitarget)(nil))
-	}
-
-	confSystem := config.GetOrCreateSystem()
-	if err := updateOrCreateSystem(confSystem, yh.osClient); err != nil {
+	_, err := yh.updateOrCreateSystem(yh.osClient)
+	if err != nil {
 		return err
 	}
 	return nil
 }
 
 func (yh *SystemHandler) Update(c ygot.ValidatedGoStruct, jobs []*gnmi.Update) error {
-	fmt.Println("Update request received for ", yh.name)
+	fmt.Println("Update request received for ", yh.Name)
 	return nil
 }
 
-func updateOrCreateSystem(confSystem *gnmitargetygot.OpenconfigSystem_System, os osclient.Osclient) error {
+func (yh *SystemHandler) updateOrCreateSystem(os osclient.Osclient) ([]*gnmi.Notification, error) {
+	yh.Config.Lock()
+	defer yh.Config.Unlock()
+
+	copyCurrentConfig, err := ygot.DeepCopy(yh.Config.Data)
+	if err != nil {
+		return nil, err
+	}
+
+	newConfig, ok := copyCurrentConfig.(*gnmitargetygot.Gnmitarget)
+	if !ok {
+		return nil, fmt.Errorf("Wrong type, exptected: %T, got: %T", (*gnmitargetygot.OpenconfigInterfaces_Interfaces)(nil), copyCurrentConfig)
+	}
+
+	confSystem := newConfig.GetOrCreateSystem()
+
 	if config := confSystem.GetOrCreateConfig(); config != nil {
 		domain, err := os.GetDomainName()
 		if err != nil {
-			return err
+			return nil, err
 		}
 		config.DomainName = ygot.String(domain)
 	}
@@ -69,9 +76,16 @@ func updateOrCreateSystem(confSystem *gnmitargetygot.OpenconfigSystem_System, os
 	}
 
 	//validate struct
-	if err := confSystem.Validate(); err != nil {
-		return err
+	if err := newConfig.Validate(); err != nil {
+		return nil, err
 	}
 
-	return nil
+	notifications, err := ygot.DiffWithAtomic(yh.Config.Data, newConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	yh.Config.Data = newConfig
+
+	return notifications, nil
 }
diff --git a/examples/example01/target.Dockerfile b/examples/example01/target.Dockerfile
index a3be6b8a65f7408370c16e1e99304ec54e61b288..b4112efd204057c92b8739ec07d09f142abe39e9 100644
--- a/examples/example01/target.Dockerfile
+++ b/examples/example01/target.Dockerfile
@@ -1,4 +1,4 @@
-ARG GOLANG_VERSION=1.21
+ARG GOLANG_VERSION=1.22
 ARG GITLAB_PROXY
 ARG BUILDARGS
 
diff --git a/go.mod b/go.mod
index 31bbcec33913513d55ecafe512681f5b000fb148..84e3122e9cc4df4245ae027d677a3dd9cb2d40a2 100644
--- a/go.mod
+++ b/go.mod
@@ -1,8 +1,6 @@
 module code.fbi.h-da.de/danet/gnmi-target
 
-go 1.21
-
-toolchain go1.22.1
+go 1.22
 
 require (
 	github.com/golang/glog v1.2.0
@@ -19,6 +17,7 @@ require (
 	golang.org/x/net v0.22.0
 	golang.org/x/sys v0.18.0
 	google.golang.org/grpc v1.61.1
+	google.golang.org/protobuf v1.33.0
 )
 
 require (
@@ -47,7 +46,6 @@ require (
 	golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
 	golang.org/x/text v0.14.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
-	google.golang.org/protobuf v1.33.0 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 3ecddbaedf3ff3d20ef7c01cc9ac384d60fa3a0c..f83fbebb444d688be20fd0c9ea3fcfc4392ec16a 100644
--- a/go.sum
+++ b/go.sum
@@ -14,6 +14,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -21,6 +22,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
 github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
 github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -43,8 +45,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
-github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -63,7 +63,9 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T
 github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
 github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
@@ -71,7 +73,6 @@ github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3v
 github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/openconfig/gnmi v0.10.0 h1:kQEZ/9ek3Vp2Y5IVuV2L/ba8/77TgjdXg505QXvYmg8=
 github.com/openconfig/gnmi v0.10.0/go.mod h1:Y9os75GmSkhHw2wX8sMsxfI7qRGAEcDh8NTa5a8vj6E=
 github.com/openconfig/gnmi v0.11.0 h1:H7pLIb/o3xObu3+x0Fv9DCK7TH3FUh7mNwbYe+34hFw=
 github.com/openconfig/gnmi v0.11.0/go.mod h1:9oJSQPPCpNvfMRj8e4ZoLVAw4wL8HyxXbiDlyuexCGU=
@@ -87,14 +88,14 @@ github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6
 github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
-github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
 github.com/prometheus/procfs v0.13.0 h1:GqzLlQyfsPbaEHaQkO7tbDlriv/4o5Hudv6OXHGKX7o=
 github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43ZKY6tow0Y1g=
 github.com/protocolbuffers/txtpbfmt v0.0.0-20220608084003-fc78c767cd6a/go.mod h1:KjY0wibdYKc4DYkerHSbguaf3JeIPGhNJBp2BNiFH78=
 github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
+github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
 github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
@@ -167,8 +168,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
-golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
 golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -191,8 +190,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
-golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
 golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -248,12 +245,11 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
-google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
-google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
 google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
 gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/handler/handler.go b/handler/handler.go
index e2eb191935164ee197d11d15ccd9cae20430b9b9..7ed5fdd6935a81416dac652989ebef4ac394140f 100644
--- a/handler/handler.go
+++ b/handler/handler.go
@@ -1,10 +1,38 @@
 package handler
 
 import (
+	"fmt"
+	"sync"
+
 	"github.com/openconfig/gnmi/proto/gnmi"
 	"github.com/openconfig/ygot/ygot"
 )
 
+// Config holds the current configuration of the device.
+// Config is used by the gnmiserver to address GET/SET requests.
+// Handlers can use config to e.g. react to internal changes and adjust the
+// configuration data accordingly.
+type Config struct {
+	Data ygot.ValidatedGoStruct
+	mu   sync.RWMutex
+}
+
+func (c *Config) Lock() {
+	c.mu.Lock()
+}
+
+func (c *Config) Unlock() {
+	c.mu.Unlock()
+}
+
+func (c *Config) RLock() {
+	c.mu.RLock()
+}
+
+func (c *Config) RUnlock() {
+	c.mu.RUnlock()
+}
+
 // PathHandler handles configuration changes and adjusts the targets config
 // model accordingly.
 //
@@ -24,9 +52,9 @@ import (
 // Therefore the configuration data (containing the new changes) is provided,
 // aswell as the single changes as gnmi.Update.
 type PathHandler interface {
-	Name() string
-	Paths() map[string]struct{}
-	Init(ygot.ValidatedGoStruct) error
+	GetName() string
+	GetPaths() map[string]struct{}
+	Init(*Config, func([]*gnmi.Notification) error) error
 	// NOTE:  Processing order as defined in the gNMI Spec 3.4: Delete,
 	// Replace, Update
 	// TODO: Add Delete and Replace
@@ -41,3 +69,31 @@ type HandlerJob struct {
 	Updates []*gnmi.Update
 	Deletes []*gnmi.Path
 }
+
+// DefaultPathHandler should be embeded by all PathHandlers to provide a default
+// implementation of the PathHandler interface. Config and the PublishToSubs
+// function are provided through the Init() function of the PathHandler.
+// Init is called for each handler when the gnmitargets `Start()`
+// method is called.
+type DefaultPathHandler struct {
+	Name          string
+	Paths         map[string]struct{}
+	Config        *Config
+	PublishToSubs func([]*gnmi.Notification) error
+}
+
+func (dph *DefaultPathHandler) GetName() string {
+	return dph.Name
+}
+
+func (dph *DefaultPathHandler) GetPaths() map[string]struct{} {
+	return dph.Paths
+}
+
+func (dpb *DefaultPathHandler) Init(*Config, func([]*gnmi.Notification) error) error {
+	return fmt.Errorf("not implemented")
+}
+
+func (dph *DefaultPathHandler) Update(ygot.ValidatedGoStruct, []*gnmi.Update) error {
+	return fmt.Errorf("not implemented")
+}
diff --git a/internal/gnmiserver/server.go b/internal/gnmiserver/server.go
index e9af0be4178e275aeef533f0e2a97ee9656da1dd..e74732f9a4eb9cf3d796e51c3df72101e1d705b9 100644
--- a/internal/gnmiserver/server.go
+++ b/internal/gnmiserver/server.go
@@ -21,10 +21,9 @@ import (
 	"compress/gzip"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"reflect"
 	"strconv"
-	"sync"
 	"time"
 
 	"golang.org/x/net/context"
@@ -32,15 +31,16 @@ import (
 	"google.golang.org/grpc/status"
 
 	log "github.com/golang/glog"
-	"github.com/golang/protobuf/proto"
 	"github.com/openconfig/gnmi/value"
 	"github.com/openconfig/ygot/util"
 	"github.com/openconfig/ygot/ygot"
 	"github.com/openconfig/ygot/ytypes"
+	"google.golang.org/protobuf/proto"
 
 	"code.fbi.h-da.de/danet/gnmi-target/handler"
 	not "code.fbi.h-da.de/danet/gnmi-target/internal/notifications"
 	dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
+	"github.com/openconfig/gnmi/proto/gnmi"
 	pb "github.com/openconfig/gnmi/proto/gnmi"
 )
 
@@ -72,17 +72,17 @@ var (
 //			//
 //			// Do something ...
 //	}
+
 type Server struct {
 	model *Model
 
-	config                    ygot.ValidatedGoStruct
-	mu                        sync.RWMutex // mu is the RW lock to protect the access to config
+	config                    *handler.Config
 	YangModelChangeDispatcher *not.Dispatcher
 	handlers                  []handler.PathHandler
 }
 
 // NewServer creates an instance of Server with given json config.
-func NewServer(model *Model, config ygot.ValidatedGoStruct, notifications *not.Dispatcher, handlers ...handler.PathHandler) (*Server, error) {
+func NewServer(model *Model, config *handler.Config, notifications *not.Dispatcher, handlers ...handler.PathHandler) (*Server, error) {
 	/*rootStruct, err := model.NewConfigStruct(config)
 	if err != nil {
 		return nil, err
@@ -104,7 +104,7 @@ func NewServer(model *Model, config ygot.ValidatedGoStruct, notifications *not.D
 // callback is used to apply a validated new config to the physical device. The
 // changed values are then sent to YangHandlers to apply the new config values
 // to the physical device.
-func (s *Server) callback(newConfig ygot.ValidatedGoStruct, existingConf ygot.ValidatedGoStruct) error {
+func (s *Server) callback(newConfig ygot.ValidatedGoStruct, existingConf ygot.ValidatedGoStruct) ([]*gnmi.Notification, error) {
 	// All applied successfully, so time for finding the diff and report this
 	// Generate gnmi notifications for subscribe
 	configDiff, err := ygot.DiffWithAtomic(existingConf, newConfig)
@@ -123,7 +123,7 @@ func (s *Server) callback(newConfig ygot.ValidatedGoStruct, existingConf ygot.Va
 	for _, handler := range s.handlers {
 		handlerJobs, err := checkHandlerPaths(handler, configDiff)
 		if err != nil {
-			return err
+			return nil, err
 		}
 		if len(handlerJobs) != 0 {
 			for _, handlerJob := range handlerJobs {
@@ -132,20 +132,26 @@ func (s *Server) callback(newConfig ygot.ValidatedGoStruct, existingConf ygot.Va
 				//	return err
 				//}
 				if err := handler.Update(newConfig, handlerJob.Updates); err != nil {
-					return err
+					return nil, err
 				}
 			}
 		}
 	}
 
-	//NOTE: There shoud be a better place for this.
-	// Run through configDiff and generate Publish events...
-	for _, specificDiff := range configDiff {
+	return configDiff, nil
+}
+
+// TODO: This will be moved
+func (s *Server) PublishNotificationsToSubscribers(notifications []*gnmi.Notification) error {
+	for _, specificDiff := range notifications {
 		// First for gnmi Updates
 		updates := specificDiff.GetUpdate()
 
 		for _, specificUpdate := range updates {
-			pathString, _ := ygot.PathToString(specificUpdate.Path)
+			pathString, err := ygot.PathToString(specificUpdate.Path)
+			if err != nil {
+				return err
+			}
 			log.Infof("specificDiff update %s with value of %s", pathString, specificUpdate.Val.String())
 			// Wrap Update into a notification and ship it off
 			updateNotification := createUpdateNotification(specificUpdate)
@@ -156,7 +162,10 @@ func (s *Server) callback(newConfig ygot.ValidatedGoStruct, existingConf ygot.Va
 		deletes := specificDiff.GetDelete()
 
 		for _, specificDelete := range deletes {
-			pathString, _ := ygot.PathToString(specificDelete)
+			pathString, err := ygot.PathToString(specificDelete)
+			if err != nil {
+				return err
+			}
 			log.Infof("specificDiff delete %s ", pathString)
 			// Wrap Update into a notification and ship it off
 			updateNotification := createDeleteNotification(specificDelete)
@@ -405,7 +414,7 @@ func getGNMIServiceVersion() (*string, error) {
 		return nil, fmt.Errorf("error in initializing gzip reader: %v", err)
 	}
 	defer r.Close()
-	b, err := ioutil.ReadAll(r)
+	b, err := io.ReadAll(r)
 	if err != nil {
 		return nil, fmt.Errorf("error in reading gzip data: %v", err)
 	}
@@ -413,10 +422,7 @@ func getGNMIServiceVersion() (*string, error) {
 	if err := proto.Unmarshal(b, desc); err != nil {
 		return nil, fmt.Errorf("error in unmarshaling proto: %v", err)
 	}
-	ver, err := proto.GetExtension(desc.Options, pb.E_GnmiService)
-	if err != nil {
-		return nil, fmt.Errorf("error in getting version from proto extension: %v", err)
-	}
+	ver := proto.GetExtension(desc.Options, pb.E_GnmiService)
 	return ver.(*string), nil
 }
 
@@ -570,8 +576,8 @@ func (s *Server) Get(ctx context.Context, req *pb.GetRequest) (*pb.GetResponse,
 	paths := req.GetPath()
 	notifications := make([]*pb.Notification, len(paths))
 
-	s.mu.RLock()
-	defer s.mu.RUnlock()
+	s.config.RLock()
+	defer s.config.RUnlock()
 
 	for i, path := range paths {
 		// Get schema node for path from config struct.
@@ -582,7 +588,7 @@ func (s *Server) Get(ctx context.Context, req *pb.GetRequest) (*pb.GetResponse,
 		if fullPath.GetElem() == nil && fullPath.GetElement() != nil {
 			return nil, status.Error(codes.Unimplemented, "deprecated path element type is unsupported")
 		}
-		nodes, err := ytypes.GetNode(s.model.schemaTreeRoot, s.config, fullPath)
+		nodes, err := ytypes.GetNode(s.model.schemaTreeRoot, s.config.Data, fullPath)
 		if len(nodes) == 0 || err != nil || util.IsValueNil(nodes[0].Data) {
 			return nil, status.Errorf(codes.NotFound, "path %v not found: %v", fullPath, err)
 		}
@@ -676,11 +682,11 @@ func (s *Server) Get(ctx context.Context, req *pb.GetRequest) (*pb.GetResponse,
 
 // Set implements the Set RPC in gNMI spec.
 func (s *Server) Set(ctx context.Context, req *pb.SetRequest) (*pb.SetResponse, error) {
-	s.mu.Lock()
-	defer s.mu.Unlock()
+	s.config.Lock()
+	defer s.config.Unlock()
 
 	// Obtain current configuration as JSON
-	jsonTree, err := ygot.ConstructIETFJSON(s.config, &ygot.RFC7951JSONConfig{})
+	jsonTree, err := ygot.ConstructIETFJSON(s.config.Data, &ygot.RFC7951JSONConfig{})
 	if err != nil {
 		msg := fmt.Sprintf("error in constructing IETF JSON tree from config struct: %v", err)
 		log.Error(msg)
@@ -717,19 +723,18 @@ func (s *Server) Set(ctx context.Context, req *pb.SetRequest) (*pb.SetResponse,
 		return nil, status.Error(codes.Internal, err.Error())
 	}
 
-	currentConfig, err := ygot.DeepCopy(s.config)
+	currentConfig, err := ygot.DeepCopy(s.config.Data)
 	if err != nil {
 		return nil, status.Error(codes.Internal, err.Error())
 	}
 
 	// Apply the validated operations to the device.
-	if s.callback != nil {
-		if applyErr := s.callback(newConfig, currentConfig.(ygot.ValidatedGoStruct)); applyErr != nil {
-			if rollbackErr := s.callback(currentConfig.(ygot.ValidatedGoStruct), s.config); rollbackErr != nil {
-				return nil, status.Errorf(codes.Internal, "error in rollback the failed operation (%v): %v", applyErr, rollbackErr)
-			}
-			return nil, status.Errorf(codes.Aborted, "error in applying operation to device: %v", applyErr)
+	diff, applyErr := s.callback(newConfig, currentConfig.(ygot.ValidatedGoStruct))
+	if applyErr != nil {
+		if _, rollbackErr := s.callback(currentConfig.(ygot.ValidatedGoStruct), s.config.Data); rollbackErr != nil {
+			return nil, status.Errorf(codes.Internal, "error in rollback the failed operation (%v): %v", applyErr, rollbackErr)
 		}
+		return nil, status.Errorf(codes.Aborted, "error in applying operation to device: %v", applyErr)
 	}
 
 	jsonDump, err := json.Marshal(jsonTree)
@@ -744,7 +749,16 @@ func (s *Server) Set(ctx context.Context, req *pb.SetRequest) (*pb.SetResponse,
 		log.Error(msg)
 		return nil, status.Error(codes.Internal, msg)
 	}
-	s.config = rootStruct
+	s.config.Data = rootStruct
+
+	// notify subscribers about the changes
+	err = s.PublishNotificationsToSubscribers(diff)
+	if err != nil {
+		msg := fmt.Sprintf("error while publishing config changes to subscribers: %v", err)
+		log.Error(msg)
+		return nil, status.Error(codes.Internal, msg)
+	}
+
 	return &pb.SetResponse{
 		Prefix:    req.GetPrefix(),
 		Response:  results,
@@ -755,7 +769,7 @@ func (s *Server) Set(ctx context.Context, req *pb.SetRequest) (*pb.SetResponse,
 // InternalUpdate is an experimental feature to let the server update its
 // internal states. Use it with your own risk.
 func (s *Server) InternalUpdate(fp func(config *ygot.ValidatedGoStruct) error) error {
-	s.mu.Lock()
-	defer s.mu.Unlock()
-	return fp(&s.config)
+	s.config.Lock()
+	defer s.config.Unlock()
+	return fp(&s.config.Data)
 }
diff --git a/internal/gnmiserver/subscribe.go b/internal/gnmiserver/subscribe.go
index 4bc3f421a9c3a84cf61f88f9c7b592864caf998d..9a15c9a70edcbb5ced10aaa478daa418fe9be960 100644
--- a/internal/gnmiserver/subscribe.go
+++ b/internal/gnmiserver/subscribe.go
@@ -37,7 +37,7 @@ func (s *Server) Subscribe(stream gnmi.GNMI_SubscribeServer) error {
 		// NOTE: Using ytypes.GetNode might not be the best solution to
 		// check if a given path exists. Since we do not really care about
 		// the node at all in this case.
-		if _, err := ytypes.GetNode(s.model.schemaTreeRoot, s.config, sub.GetPath()); err != nil {
+		if _, err := ytypes.GetNode(s.model.schemaTreeRoot, s.config.Data, sub.GetPath()); err != nil {
 			return status.Error(codes.Internal, fmt.Sprintf("The provided path: %s, does not exist, subscribe not possible.", path.String()))
 		}
 
@@ -112,7 +112,7 @@ func (s *Server) streamOnChangeSubscriptionHandler(notificationSubscriber *notif
 			log.Error(err)
 			return
 		}
-		node, err := ytypes.GetNode(s.model.schemaTreeRoot, s.config, path)
+		node, err := ytypes.GetNode(s.model.schemaTreeRoot, s.config.Data, path)
 		if err != nil {
 			log.Error(err)
 			return
diff --git a/internal/gnmiserver/util.go b/internal/gnmiserver/util.go
index c824f72082fc63ecbf0731b43361a191c2e40314..e45a8ad73ce786c0c600478ce7cbdf8bfb4386a3 100644
--- a/internal/gnmiserver/util.go
+++ b/internal/gnmiserver/util.go
@@ -136,7 +136,7 @@ func createDeleteNotification(deletedPath *pb.Path) *pb.Notification {
 func checkHandlerPaths(h handler.PathHandler, diffs []*pb.Notification) ([]*handler.HandlerJob, error) {
 	jobs := make([]*handler.HandlerJob, 0)
 
-	for topic, _ := range h.Paths() {
+	for topic := range h.GetPaths() {
 		for _, diff := range diffs {
 			var updates []*gnmi.Update
 			for _, update := range diff.GetUpdate() {
diff --git a/internal/notifications/notifications.go b/internal/notifications/notifications.go
index d36f9a50419f8b9904302ffe2703be6b4fc71f4b..0d30b7aea7c1f028a6ad758e5db368f45e5c9248 100644
--- a/internal/notifications/notifications.go
+++ b/internal/notifications/notifications.go
@@ -123,6 +123,7 @@ func (b *Dispatcher) Publish(stringPath string, msg *gnmi.Notification) {
 		//TODO: handle error
 	}
 	topics, err := pathToStringList(path)
+	log.Debugf("topics: %v", topics)
 	if err != nil {
 		//TODO: handle error
 	}
@@ -130,7 +131,7 @@ func (b *Dispatcher) Publish(stringPath string, msg *gnmi.Notification) {
 		b.mu.RLock()
 		interestedSubscribers := b.topics[topic]
 		b.mu.RUnlock()
-		log.Debug("checking topic: %s, has %d subscribers\n", topic, len(interestedSubscribers))
+		log.Debugf("checking topic: %s, has %d subscribers\n", topic, len(interestedSubscribers))
 		for _, s := range interestedSubscribers {
 			m := NewInfoChangeMessage(msg, stringPath)
 			if !s.active {
@@ -145,7 +146,7 @@ func (b *Dispatcher) Publish(stringPath string, msg *gnmi.Notification) {
 
 // TODO: rename and add description
 func pathToStringList(path *gnmi.Path) ([]string, error) {
-	paths := make([]string, 0)
+	paths := []string{"/"}
 	for p := path; len(p.Elem) != 0; p.Elem = p.Elem[:len(p.Elem)-1] {
 		pathStrings, err := ygot.PathToStrings(path)
 		if err != nil {
@@ -211,7 +212,7 @@ func (s *Subscriber) GetTopics() []string {
 	s.mutex.RLock()
 	defer s.mutex.RUnlock()
 	topics := []string{}
-	for topic, _ := range s.topics {
+	for topic := range s.topics {
 		topics = append(topics, topic)
 	}
 	return topics
diff --git a/target.go b/target.go
index 04f0b66411fb977f22c8845a2aa8da943a638683..02230ecb6bf697abe9145ad9c476f635e317180a 100644
--- a/target.go
+++ b/target.go
@@ -77,17 +77,21 @@ func (gt *GnmiTarget) Start(bindAddress string, certFile string, keyFile string,
 		}
 	}
 
-	for _, handler := range gt.yangHandlers {
-		if err := handler.Init(gt.model); err != nil {
-			log.Fatalf("error in initializing GNMI target through handlers: %v", err)
-		}
+	config := &handler.Config{
+		Data: gt.model,
 	}
 
-	gnmiServer, err := server.NewServer(gnmiModel, gt.model, gt.YangModelChangeDispatcher, gt.yangHandlers...)
+	gnmiServer, err := server.NewServer(gnmiModel, config, gt.YangModelChangeDispatcher, gt.yangHandlers...)
 	if err != nil {
 		log.Fatalf("error in creating GNMI target: %v", err)
 	}
 
+	for _, handler := range gt.yangHandlers {
+		if err := handler.Init(config, gnmiServer.PublishNotificationsToSubscribers); err != nil {
+			log.Fatalf("error in initializing GNMI target through handlers: %v", err)
+		}
+	}
+
 	var grpcServer *grpc.Server
 
 	if insecure == false {