diff --git a/controller/interfaces/plugin/plugin.go b/controller/interfaces/plugin/plugin.go
index 6835b7e738b764149bac026232a0fd4d35d43208..dc01a0ee8145f5638cd4ca92d0bfa5b3017b68fe 100644
--- a/controller/interfaces/plugin/plugin.go
+++ b/controller/interfaces/plugin/plugin.go
@@ -36,14 +36,14 @@ const (
 	FAULTY
 )
 
-// Plugin describes an interface for a plugin within the controller - a plugin
-// in the context of the controller is a basic go plugin. A plugin satisfies
-// the Storable interface and can be stored.
+// Plugin describes an interface for a plugin within the controller. A plugin
+// is based on hashicorp's `go plugin`.
 type Plugin interface {
 	ID() uuid.UUID
 	GetClient() *hcplugin.Client
 	State() State
 	Manifest() *Manifest
+	ExecPath() string
 	Update() error
 	Ping() error
 	Restart() error
@@ -123,7 +123,11 @@ type LoadedPlugin struct {
 	// Manifest represents the manifest of the LoadedPlugin.
 	Manifest Manifest `json:"manifest" bson:"manifest"`
 	// State represents the state of the LoadedPlugin.
-	State          State                   `json:"state,omitempty" bson:"state"`
+	State State `json:"state,omitempty" bson:"state"`
+	// ExecPath represents the path to the executable of the plugin.
+	ExecPath string `json:"exec_path,omitempty" bson:"exec_path"`
+	// ReattachConfig represents the configuration to reattach to a already
+	// running plugin.
 	ReattachConfig hcplugin.ReattachConfig `json:"reattatch_config,omitempty" bson:"reattatch_config"`
 }
 
@@ -136,6 +140,7 @@ func (lp *LoadedPlugin) UnmarshalBSON(data []byte) error {
 	lp.ID = loadedPluginHelper.ID
 	lp.Manifest = loadedPluginHelper.Manifest
 	lp.State = loadedPluginHelper.State
+	lp.ExecPath = loadedPluginHelper.ExecPath
 	lp.ReattachConfig = hcplugin.ReattachConfig{
 		Protocol:        hcplugin.Protocol(loadedPluginHelper.ReattachConfig.Protocol),
 		ProtocolVersion: loadedPluginHelper.ReattachConfig.ProtocolVersion,
@@ -159,6 +164,7 @@ func (lp *LoadedPlugin) UnmarshalJSON(data []byte) error {
 	lp.ID = loadedPluginHelper.ID
 	lp.Manifest = loadedPluginHelper.Manifest
 	lp.State = loadedPluginHelper.State
+	lp.ExecPath = loadedPluginHelper.ExecPath
 	lp.ReattachConfig = hcplugin.ReattachConfig{
 		Protocol:        hcplugin.Protocol(loadedPluginHelper.ReattachConfig.Protocol),
 		ProtocolVersion: loadedPluginHelper.ReattachConfig.ProtocolVersion,
@@ -177,6 +183,7 @@ type LoadedPluginHelper struct {
 	ID             string               `json:"id" bson:"_id"`
 	Manifest       Manifest             `json:"manifest" bson:"manifest"`
 	State          State                `json:"state,omitempty" bson:"state"`
+	ExecPath       string               `json:"exec_path,omitempty" bson:"exec_path"`
 	ReattachConfig LoadedReattachConfig `json:"reattatch_config,omitempty" bson:"reattatch_config"`
 }
 
diff --git a/controller/mocks/Plugin.go b/controller/mocks/Plugin.go
index a9fd4e3508a08437f9ddea704aaed12f6e83aa8b..aa33c39de6ae2a0f7a92f63a5374bc6dcf4af401 100644
--- a/controller/mocks/Plugin.go
+++ b/controller/mocks/Plugin.go
@@ -65,6 +65,20 @@ func (_m *Plugin) Diff(original []byte, modified []byte) (*gnmi.Notification, er
 	return r0, r1
 }
 
+// ExecPath provides a mock function with given fields:
+func (_m *Plugin) ExecPath() string {
+	ret := _m.Called()
+
+	var r0 string
+	if rf, ok := ret.Get(0).(func() string); ok {
+		r0 = rf()
+	} else {
+		r0 = ret.Get(0).(string)
+	}
+
+	return r0
+}
+
 // GetClient provides a mock function with given fields:
 func (_m *Plugin) GetClient() *go_plugin.Client {
 	ret := _m.Called()
diff --git a/controller/nucleus/plugin.go b/controller/nucleus/plugin.go
index 8851e16a9aa8248cde209faa9921ef2cc2001609..adc0312b3d41c5ba03d695dcead5232d51e9563a 100644
--- a/controller/nucleus/plugin.go
+++ b/controller/nucleus/plugin.go
@@ -4,9 +4,11 @@ import (
 	"encoding/json"
 	"fmt"
 	"os/exec"
+	"path/filepath"
 
 	"code.fbi.h-da.de/danet/gosdn/controller/customerrs"
 	"code.fbi.h-da.de/danet/gosdn/controller/interfaces/plugin"
+	"code.fbi.h-da.de/danet/gosdn/controller/nucleus/util"
 	"code.fbi.h-da.de/danet/gosdn/controller/plugin/shared"
 	"github.com/google/uuid"
 	hcplugin "github.com/hashicorp/go-plugin"
@@ -16,25 +18,21 @@ import (
 type Plugin struct {
 	UUID     uuid.UUID
 	state    plugin.State
-	path     string
+	execPath string
 	manifest *plugin.Manifest
 	client   *hcplugin.Client
 	shared.DeviceModel
 }
 
-func NewPlugin(id uuid.UUID) (*Plugin, error) {
-	if id == uuid.Nil {
-		id = uuid.New()
-	}
-
+func NewPlugin(id uuid.UUID, execPath string) (*Plugin, error) {
 	client := hcplugin.NewClient(&hcplugin.ClientConfig{
 		HandshakeConfig:  shared.Handshake,
 		Plugins:          shared.PluginMap,
-		Cmd:              exec.Command("sh", "-c", fmt.Sprintf("plugins/%s/plugin", id.String())),
+		Cmd:              exec.Command("sh", "-c", filepath.Join(execPath, util.PluginExecutableName)),
 		AllowedProtocols: []hcplugin.Protocol{hcplugin.ProtocolGRPC},
 	})
 
-	manifest, err := plugin.ReadManifestFromFile(fmt.Sprintf("plugins/%s", id.String()))
+	manifest, err := plugin.ReadManifestFromFile(execPath)
 	if err != nil {
 		return nil, err
 	}
@@ -62,6 +60,7 @@ func NewPlugin(id uuid.UUID) (*Plugin, error) {
 	return &Plugin{
 		UUID:        id,
 		client:      client,
+		execPath:    execPath,
 		DeviceModel: model,
 		manifest:    manifest,
 		state:       plugin.CREATED,
@@ -124,8 +123,8 @@ func (p *Plugin) State() plugin.State {
 	return p.state
 }
 
-func (p *Plugin) Path() string {
-	return p.path
+func (p *Plugin) ExecPath() string {
+	return p.execPath
 }
 
 // GetClient returns the client of the plugin.
@@ -173,11 +172,13 @@ func (p *Plugin) MarshalJSON() ([]byte, error) {
 		ID             uuid.UUID                `json:"id,omitempty"`
 		Manifest       *plugin.Manifest         `json:"manifest" bson:"manifest"`
 		State          plugin.State             `json:"state,omitempty" bson:"state"`
+		ExecPath       string                   `json:"exec_path,omitempty" bson:"exec_path"`
 		ReattachConfig *hcplugin.ReattachConfig `json:"reattatch_config,omitempty" bson:"reattatch_config"`
 	}{
 		ID:             p.ID(),
 		Manifest:       p.Manifest(),
 		State:          p.State(),
+		ExecPath:       p.ExecPath(),
 		ReattachConfig: p.ReattachConfig(),
 	})
 }
@@ -187,11 +188,13 @@ func (p *Plugin) MarshalBSON() ([]byte, error) {
 		ID             string                   `bson:"_id,omitempty"`
 		Manifest       *plugin.Manifest         `json:"manifest" bson:"manifest"`
 		State          plugin.State             `json:"state,omitempty" bson:"state"`
+		ExecPath       string                   `json:"exec_path,omitempty" bson:"exec_path"`
 		ReattachConfig *hcplugin.ReattachConfig `json:"reattatch_config,omitempty" bson:"reattatch_config"`
 	}{
 		ID:             p.ID().String(),
 		Manifest:       p.Manifest(),
 		State:          p.State(),
+		ExecPath:       p.ExecPath(),
 		ReattachConfig: p.ReattachConfig(),
 	})
 }
diff --git a/controller/nucleus/pluginService.go b/controller/nucleus/pluginService.go
index 2a8c28c80da6f63c412de938133f56001607f31f..ed7a7ab689cd65e1c7f8ae408de107812a1f454b 100644
--- a/controller/nucleus/pluginService.go
+++ b/controller/nucleus/pluginService.go
@@ -5,6 +5,7 @@ import (
 	"errors"
 	"fmt"
 	"io"
+	"io/fs"
 	"os"
 	"path/filepath"
 	"strings"
@@ -118,7 +119,7 @@ func (s *PluginService) createPluginFromStore(loadedPlugin plugin.LoadedPlugin)
 	plugin, err := s.createPluginFromStoreFn(loadedPlugin)
 	if err != nil {
 		if errors.Is(err, hcplugin.ErrProcessNotFound) {
-			plugin, err = NewPlugin(uuid.MustParse(loadedPlugin.ID))
+			plugin, err = NewPlugin(uuid.MustParse(loadedPlugin.ID), loadedPlugin.ExecPath)
 			if err != nil {
 				return nil, err
 			}
@@ -144,20 +145,24 @@ func (s *PluginService) RequestPlugin(requestID uuid.UUID) (plugin.Plugin, error
 		Id:        requestID.String(),
 	}
 
-	dClient, err := s.pluginRegistryClient.Download(ctx, pluginDownloadRequest)
-	if err != nil {
-		return nil, err
-	}
+	folderName := viper.GetString("plugin-folder")
+	path := filepath.Join(folderName, requestID.String())
+	if _, err := os.Stat(filepath.Join(path, util.PluginExecutableName)); errors.Is(err, fs.ErrNotExist) {
+		dClient, err := s.pluginRegistryClient.Download(ctx, pluginDownloadRequest)
+		if err != nil {
+			return nil, err
+		}
 
-	if err := saveStreamToFile(dClient, util.BundledPluginName, requestID); err != nil {
-		return nil, err
-	}
+		if err := saveStreamToFile(dClient, util.BundledPluginName, requestID); err != nil {
+			return nil, err
+		}
 
-	if err := util.UnzipPlugin(requestID); err != nil {
-		return nil, err
+		if err := util.UnzipPlugin(requestID); err != nil {
+			return nil, err
+		}
 	}
 
-	plugin, err := NewPlugin(requestID)
+	plugin, err := NewPlugin(uuid.New(), path)
 	if err != nil {
 		return nil, err
 	}
diff --git a/controller/nucleus/util/plugin.go b/controller/nucleus/util/plugin.go
index a0e90b2d37ddf8edeb744c8a722b76a1546c575d..9d78e96740961b39256cea28d269e6fcc2ddbad0 100644
--- a/controller/nucleus/util/plugin.go
+++ b/controller/nucleus/util/plugin.go
@@ -12,6 +12,8 @@ import (
 
 // TODO: can be private in the future.
 const (
+	// PluginExecutableName references the unzippped name of a plugin.
+	PluginExecutableName string = "plugin"
 	// ManifestFileName references the name of a manifest file that has been
 	// requested while creating a new device of type plugin/csbi.
 	ManifestFileName string = "plugin.yaml"