Repository: kubernetes-sigs/node-feature-discovery
Pull request #912 (2022-10-12 11:06:06)

apis/nfd: migrate pkg/api/feature
Move the previously-protobuf-only internal "feature api" over to the
public "nfd api" package. This is in preparation for introducing a new
CRD API for communicating features.

This patch carries no functional changes. Just moving code around.

Split out from #903 

k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/node-feature-discovery/pull/912#" title="Author self-approved">marquiz</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fnode-feature-discovery).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/node-feature-discovery/blob/master/OWNERS)~~ [marquiz]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy Preview for *kubernetes-sigs-nfd* processing.


|  Name | Link |
|---------------------------------|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 9b8d6d115e745e771f97b196ce68b92cb0df35a2 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/kubernetes-sigs-nfd/deploys/63469fa0155dd50009f68862 |
marquiz: Rebased

Patch:
diff --git a/pkg/api/feature/generate.sh b/pkg/api/feature/generate.sh
deleted file mode 100755
index a9785cafe..000000000
--- a/pkg/api/feature/generate.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/sh -ex
-
-# go-to-protobuf seems unable to run in the package directory -> move to parent dir
-cd ..
-go-to-protobuf \
-   --output-base=. \
-   --go-header-file ../../hack/boilerplate.go.txt \
-   --proto-import ../../vendor \
-   --packages ./feature=feature \
-   --keep-gogoproto=false \
-   --apimachinery-packages "-k8s.io/apimachinery/pkg/util/intstr"
-cd -
-
-# Mangle the go_package option to comply with newer versions protoc-gen-go
-sed s',go_package =.*,go_package = "sigs.k8s.io/node-feature-discovery/pkg/api/feature";,' \
-    -i generated.proto
diff --git a/pkg/api/feature/types.go b/pkg/api/feature/types.go
deleted file mode 100644
index 505081414..000000000
--- a/pkg/api/feature/types.go
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-Copyright 2021 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package feature
-
-//go:generate ./generate.sh
-
-// Features is a collection of all features of the system, arranged by domain.
-// +protobuf
-type Features map[string]*DomainFeatures
-
-// DomainFeatures is the collection of all discovered features of one domain.
-type DomainFeatures struct {
-	Flags      map[string]FlagFeatureSet      `protobuf:"bytes,1,rep,name=flags"`
-	Attributes map[string]AttributeFeatureSet `protobuf:"bytes,2,rep,name=vattributes"`
-	Instances  map[string]InstanceFeatureSet  `protobuf:"bytes,3,rep,name=instances"`
-}
-
-// FlagFeatureSet is a set of simple features only containing names without values.
-type FlagFeatureSet struct {
-	Elements map[string]Nil `protobuf:"bytes,1,rep,name=elements"`
-}
-
-// AttributeFeatureSet is a set of features having string value.
-type AttributeFeatureSet struct {
-	Elements map[string]string `protobuf:"bytes,1,rep,name=elements"`
-}
-
-// InstanceFeatureSet is a set of features each of which is an instance having multiple attributes.
-type InstanceFeatureSet struct {
-	Elements []InstanceFeature `protobuf:"bytes,1,rep,name=elements"`
-}
-
-// InstanceFeature represents one instance of a complex features, e.g. a device.
-type InstanceFeature struct {
-	Attributes map[string]string `protobuf:"bytes,1,rep,name=attributes"`
-}
-
-// Nil is a dummy empty struct for protobuf compatibility
-type Nil struct{}
diff --git a/pkg/apis/nfd/v1alpha1/doc.go b/pkg/apis/nfd/v1alpha1/doc.go
index 32b425965..17b8fc585 100644
--- a/pkg/apis/nfd/v1alpha1/doc.go
+++ b/pkg/apis/nfd/v1alpha1/doc.go
@@ -19,3 +19,5 @@ limitations under the License.
 // +kubebuilder:object:generate=true
 // +groupName=nfd.k8s-sigs.io
 package v1alpha1
+
+//go:generate ./generate.sh
diff --git a/pkg/apis/nfd/v1alpha1/expression.go b/pkg/apis/nfd/v1alpha1/expression.go
index fefc6c90e..47108ab22 100644
--- a/pkg/apis/nfd/v1alpha1/expression.go
+++ b/pkg/apis/nfd/v1alpha1/expression.go
@@ -25,8 +25,6 @@ import (
 	"strings"
 
 	"k8s.io/klog/v2"
-
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
 )
 
 var matchOps = map[MatchOp]struct{}{
@@ -197,7 +195,7 @@ func (m *MatchExpression) Match(valid bool, value interface{}) (bool, error) {
 }
 
 // MatchKeys evaluates the MatchExpression against a set of keys.
-func (m *MatchExpression) MatchKeys(name string, keys map[string]feature.Nil) (bool, error) {
+func (m *MatchExpression) MatchKeys(name string, keys map[string]Nil) (bool, error) {
 	matched := false
 
 	_, ok := keys[name]
@@ -303,7 +301,7 @@ func (m *MatchExpression) UnmarshalJSON(data []byte) error {
 }
 
 // MatchKeys evaluates the MatchExpressionSet against a set of keys.
-func (m *MatchExpressionSet) MatchKeys(keys map[string]feature.Nil) (bool, error) {
+func (m *MatchExpressionSet) MatchKeys(keys map[string]Nil) (bool, error) {
 	matched, _, err := m.MatchGetKeys(keys)
 	return matched, err
 }
@@ -318,7 +316,7 @@ type MatchedKey struct {
 // empty MatchExpressionSet returns all existing keys are returned. Note that
 // an empty MatchExpressionSet and an empty set of keys returns an empty slice
 // which is not nil and is treated as a match.
-func (m *MatchExpressionSet) MatchGetKeys(keys map[string]feature.Nil) (bool, []MatchedKey, error) {
+func (m *MatchExpressionSet) MatchGetKeys(keys map[string]Nil) (bool, []MatchedKey, error) {
 	ret := make([]MatchedKey, 0, len(*m))
 
 	for n, e := range *m {
@@ -374,7 +372,7 @@ func (m *MatchExpressionSet) MatchGetValues(values map[string]string) (bool, []M
 // MatchInstances evaluates the MatchExpressionSet against a set of instance
 // features, each of which is an individual set of key-value pairs
 // (attributes).
-func (m *MatchExpressionSet) MatchInstances(instances []feature.InstanceFeature) (bool, error) {
+func (m *MatchExpressionSet) MatchInstances(instances []InstanceFeature) (bool, error) {
 	v, err := m.MatchGetInstances(instances)
 	return len(v) > 0, err
 }
@@ -386,7 +384,7 @@ type MatchedInstance map[string]string
 // features, each of which is an individual set of key-value pairs
 // (attributes). A slice containing all matching instances is returned. An
 // empty (non-nil) slice is returned if no matching instances were found.
-func (m *MatchExpressionSet) MatchGetInstances(instances []feature.InstanceFeature) ([]MatchedInstance, error) {
+func (m *MatchExpressionSet) MatchGetInstances(instances []InstanceFeature) ([]MatchedInstance, error) {
 	ret := []MatchedInstance{}
 
 	for _, i := range instances {
diff --git a/pkg/api/feature/feature.go b/pkg/apis/nfd/v1alpha1/feature.go
similarity index 99%
rename from pkg/api/feature/feature.go
rename to pkg/apis/nfd/v1alpha1/feature.go
index bd23af277..b54117cfe 100644
--- a/pkg/api/feature/feature.go
+++ b/pkg/apis/nfd/v1alpha1/feature.go
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package feature
+package v1alpha1
 
 // NewDomainFeatures creates a new instance of Features, initializing specified
 // features to empty values
diff --git a/pkg/apis/nfd/v1alpha1/generate.sh b/pkg/apis/nfd/v1alpha1/generate.sh
new file mode 100755
index 000000000..d4fe85392
--- /dev/null
+++ b/pkg/apis/nfd/v1alpha1/generate.sh
@@ -0,0 +1,12 @@
+#!/bin/sh -ex
+
+go-to-protobuf \
+   --output-base=. \
+   --go-header-file ../../../../hack/boilerplate.go.txt \
+   --proto-import ../../../../vendor/ \
+   --packages +sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1=v1alpha1 \
+   --keep-gogoproto=false \
+   --apimachinery-packages "-k8s.io/apimachinery/pkg/util/intstr"
+
+mv sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1/* .
+rm -rf sigs.k8s.io
diff --git a/pkg/api/feature/generated.pb.go b/pkg/apis/nfd/v1alpha1/generated.pb.go
similarity index 90%
rename from pkg/api/feature/generated.pb.go
rename to pkg/apis/nfd/v1alpha1/generated.pb.go
index 642c1b4c2..f9f41ac6a 100644
--- a/pkg/api/feature/generated.pb.go
+++ b/pkg/apis/nfd/v1alpha1/generated.pb.go
@@ -15,9 +15,9 @@ limitations under the License.
 */
 
 // Code generated by protoc-gen-gogo. DO NOT EDIT.
-// source: feature/generated.proto
+// source: sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1/generated.proto
 
-package feature
+package v1alpha1
 
 import (
 	fmt "fmt"
@@ -46,7 +46,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 func (m *AttributeFeatureSet) Reset()      { *m = AttributeFeatureSet{} }
 func (*AttributeFeatureSet) ProtoMessage() {}
 func (*AttributeFeatureSet) Descriptor() ([]byte, []int) {
-	return fileDescriptor_870e6eafce4d2482, []int{0}
+	return fileDescriptor_6f67d44e41cfe439, []int{0}
 }
 func (m *AttributeFeatureSet) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -74,7 +74,7 @@ var xxx_messageInfo_AttributeFeatureSet proto.InternalMessageInfo
 func (m *DomainFeatures) Reset()      { *m = DomainFeatures{} }
 func (*DomainFeatures) ProtoMessage() {}
 func (*DomainFeatures) Descriptor() ([]byte, []int) {
-	return fileDescriptor_870e6eafce4d2482, []int{1}
+	return fileDescriptor_6f67d44e41cfe439, []int{1}
 }
 func (m *DomainFeatures) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -102,7 +102,7 @@ var xxx_messageInfo_DomainFeatures proto.InternalMessageInfo
 func (m *FlagFeatureSet) Reset()      { *m = FlagFeatureSet{} }
 func (*FlagFeatureSet) ProtoMessage() {}
 func (*FlagFeatureSet) Descriptor() ([]byte, []int) {
-	return fileDescriptor_870e6eafce4d2482, []int{2}
+	return fileDescriptor_6f67d44e41cfe439, []int{2}
 }
 func (m *FlagFeatureSet) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -130,7 +130,7 @@ var xxx_messageInfo_FlagFeatureSet proto.InternalMessageInfo
 func (m *InstanceFeature) Reset()      { *m = InstanceFeature{} }
 func (*InstanceFeature) ProtoMessage() {}
 func (*InstanceFeature) Descriptor() ([]byte, []int) {
-	return fileDescriptor_870e6eafce4d2482, []int{3}
+	return fileDescriptor_6f67d44e41cfe439, []int{3}
 }
 func (m *InstanceFeature) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -158,7 +158,7 @@ var xxx_messageInfo_InstanceFeature proto.InternalMessageInfo
 func (m *InstanceFeatureSet) Reset()      { *m = InstanceFeatureSet{} }
 func (*InstanceFeatureSet) ProtoMessage() {}
 func (*InstanceFeatureSet) Descriptor() ([]byte, []int) {
-	return fileDescriptor_870e6eafce4d2482, []int{4}
+	return fileDescriptor_6f67d44e41cfe439, []int{4}
 }
 func (m *InstanceFeatureSet) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -186,7 +186,7 @@ var xxx_messageInfo_InstanceFeatureSet proto.InternalMessageInfo
 func (m *Nil) Reset()      { *m = Nil{} }
 func (*Nil) ProtoMessage() {}
 func (*Nil) Descriptor() ([]byte, []int) {
-	return fileDescriptor_870e6eafce4d2482, []int{5}
+	return fileDescriptor_6f67d44e41cfe439, []int{5}
 }
 func (m *Nil) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -212,56 +212,61 @@ func (m *Nil) XXX_DiscardUnknown() {
 var xxx_messageInfo_Nil proto.InternalMessageInfo
 
 func init() {
-	proto.RegisterType((*AttributeFeatureSet)(nil), "feature.AttributeFeatureSet")
-	proto.RegisterMapType((map[string]string)(nil), "feature.AttributeFeatureSet.ElementsEntry")
-	proto.RegisterType((*DomainFeatures)(nil), "feature.DomainFeatures")
-	proto.RegisterMapType((map[string]FlagFeatureSet)(nil), "feature.DomainFeatures.FlagsEntry")
-	proto.RegisterMapType((map[string]InstanceFeatureSet)(nil), "feature.DomainFeatures.InstancesEntry")
-	proto.RegisterMapType((map[string]AttributeFeatureSet)(nil), "feature.DomainFeatures.VattributesEntry")
-	proto.RegisterType((*FlagFeatureSet)(nil), "feature.FlagFeatureSet")
-	proto.RegisterMapType((map[string]Nil)(nil), "feature.FlagFeatureSet.ElementsEntry")
-	proto.RegisterType((*InstanceFeature)(nil), "feature.InstanceFeature")
-	proto.RegisterMapType((map[string]string)(nil), "feature.InstanceFeature.AttributesEntry")
-	proto.RegisterType((*InstanceFeatureSet)(nil), "feature.InstanceFeatureSet")
-	proto.RegisterType((*Nil)(nil), "feature.Nil")
+	proto.RegisterType((*AttributeFeatureSet)(nil), "v1alpha1.AttributeFeatureSet")
+	proto.RegisterMapType((map[string]string)(nil), "v1alpha1.AttributeFeatureSet.ElementsEntry")
+	proto.RegisterType((*DomainFeatures)(nil), "v1alpha1.DomainFeatures")
+	proto.RegisterMapType((map[string]FlagFeatureSet)(nil), "v1alpha1.DomainFeatures.FlagsEntry")
+	proto.RegisterMapType((map[string]InstanceFeatureSet)(nil), "v1alpha1.DomainFeatures.InstancesEntry")
+	proto.RegisterMapType((map[string]AttributeFeatureSet)(nil), "v1alpha1.DomainFeatures.VattributesEntry")
+	proto.RegisterType((*FlagFeatureSet)(nil), "v1alpha1.FlagFeatureSet")
+	proto.RegisterMapType((map[string]Nil)(nil), "v1alpha1.FlagFeatureSet.ElementsEntry")
+	proto.RegisterType((*InstanceFeature)(nil), "v1alpha1.InstanceFeature")
+	proto.RegisterMapType((map[string]string)(nil), "v1alpha1.InstanceFeature.AttributesEntry")
+	proto.RegisterType((*InstanceFeatureSet)(nil), "v1alpha1.InstanceFeatureSet")
+	proto.RegisterType((*Nil)(nil), "v1alpha1.Nil")
 }
 
-func init() { proto.RegisterFile("feature/generated.proto", fileDescriptor_870e6eafce4d2482) }
+func init() {
+	proto.RegisterFile("sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1/generated.proto", fileDescriptor_6f67d44e41cfe439)
+}
 
-var fileDescriptor_870e6eafce4d2482 = []byte{
-	// 501 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0xdd, 0x6a, 0xd4, 0x40,
-	0x14, 0xc7, 0x33, 0xbb, 0x2e, 0x36, 0x67, 0xed, 0x76, 0x1d, 0x85, 0x86, 0x28, 0xd3, 0x12, 0x50,
-	0x16, 0xa1, 0x09, 0xee, 0x95, 0x28, 0x5e, 0xb4, 0xd8, 0x95, 0xde, 0x14, 0x4c, 0xc1, 0x2f, 0x16,
-	0x21, 0x5b, 0x67, 0x63, 0x30, 0x9b, 0x48, 0x32, 0x29, 0xf4, 0xce, 0x47, 0xf0, 0x09, 0x7c, 0x02,
-	0x11, 0x1f, 0x63, 0x2f, 0x7b, 0xd9, 0xab, 0xe2, 0xc6, 0x17, 0x91, 0x9d, 0x4c, 0x3e, 0x37, 0xd9,
-	0xd2, 0xbb, 0xcc, 0x99, 0xff, 0xf9, 0x9d, 0x73, 0xfe, 0x73, 0x02, 0xdb, 0x53, 0x6a, 0xb1, 0x28,
-	0xa0, 0x86, 0x4d, 0x3d, 0x1a, 0x58, 0x8c, 0x7e, 0xd6, 0xbf, 0x05, 0x3e, 0xf3, 0xf1, 0x6d, 0x71,
-	0xa1, 0xee, 0xd9, 0x0e, 0xfb, 0x12, 0x4d, 0xf4, 0x53, 0x7f, 0x66, 0xd8, 0xbe, 0xed, 0x1b, 0xfc,
-	0x7e, 0x12, 0x4d, 0xf9, 0x89, 0x1f, 0xf8, 0x57, 0x92, 0xa7, 0xfd, 0x42, 0x70, 0x6f, 0x9f, 0xb1,
-	0xc0, 0x99, 0x44, 0x8c, 0x8e, 0x12, 0xc6, 0x09, 0x65, 0xf8, 0x3d, 0x6c, 0x50, 0x97, 0xce, 0xa8,
-	0xc7, 0x42, 0x05, 0xed, 0xb6, 0x07, 0xdd, 0xe1, 0x13, 0x5d, 0x94, 0xd0, 0x6b, 0xf4, 0xfa, 0xa1,
-	0x10, 0x1f, 0x7a, 0x2c, 0x38, 0x3f, 0xe8, 0xcf, 0xaf, 0x76, 0xa4, 0xf8, 0x6a, 0x67, 0x23, 0x0d,
-	0x9b, 0x19, 0x4d, 0x7d, 0x01, 0x9b, 0x25, 0x31, 0xee, 0x43, 0xfb, 0x2b, 0x3d, 0x57, 0xd0, 0x2e,
-	0x1a, 0xc8, 0xe6, 0xf2, 0x13, 0xdf, 0x87, 0xce, 0x99, 0xe5, 0x46, 0x54, 0x69, 0xf1, 0x58, 0x72,
-	0x78, 0xde, 0x7a, 0x86, 0xb4, 0x9f, 0xb7, 0xa0, 0xf7, 0xca, 0x9f, 0x59, 0x8e, 0x27, 0x6a, 0x87,
-	0xf8, 0x35, 0x74, 0xa6, 0xae, 0x65, 0xa7, 0x6d, 0x6a, 0x59, 0x9b, 0x65, 0x9d, 0x3e, 0x5a, 0x8a,
-	0x92, 0xf6, 0x36, 0x45, 0x7b, 0x1d, 0x1e, 0x33, 0x93, 0x7c, 0xfc, 0x09, 0xba, 0x67, 0x56, 0x3a,
-	0x5a, 0xa8, 0xb4, 0x38, 0x6e, 0xd0, 0x84, 0x7b, 0x9b, 0x4b, 0x13, 0x28, 0x16, 0x50, 0xc8, 0xec,
-	0x09, 0xcd, 0x22, 0x10, 0xbf, 0x03, 0xd9, 0xf1, 0x42, 0x66, 0x79, 0xa7, 0x34, 0x54, 0xda, 0x9c,
-	0xfe, 0xb8, 0x89, 0x7e, 0x94, 0x0a, 0x13, 0xf6, 0x5d, 0xc1, 0x96, 0xb3, 0xb8, 0x99, 0xb3, 0xd4,
-	0x37, 0x00, 0xf9, 0x70, 0x35, 0x76, 0xee, 0x15, 0xed, 0xec, 0x0e, 0xb7, 0xb3, 0xa2, 0xcb, 0xac,
-	0xfc, 0x0d, 0x0b, 0x3e, 0xab, 0x63, 0xe8, 0x57, 0x07, 0xac, 0x01, 0x0f, 0xcb, 0xe0, 0x87, 0xeb,
-	0x36, 0xa4, 0x48, 0xff, 0x00, 0xbd, 0xf2, 0x80, 0x35, 0xec, 0xa7, 0x65, 0xf6, 0x83, 0x8c, 0x9d,
-	0x66, 0xd6, 0xa2, 0xb5, 0x3f, 0x08, 0x7a, 0xe5, 0xb1, 0xf0, 0xc9, 0xca, 0x2a, 0x3f, 0x6a, 0x70,
-	0xe0, 0x06, 0x5b, 0x7c, 0x74, 0xfd, 0x16, 0x6b, 0xe5, 0x09, 0xee, 0x64, 0x45, 0x8f, 0x1d, 0xb7,
-	0xd8, 0xf2, 0x6f, 0x04, 0x5b, 0x95, 0xa1, 0xf0, 0x18, 0xa0, 0xb0, 0x8a, 0xa8, 0xb2, 0x8a, 0x15,
-	0x75, 0x6e, 0xf7, 0x9a, 0x55, 0x2c, 0xf0, 0xd4, 0x97, 0xb0, 0xb5, 0x7f, 0xed, 0xe3, 0x36, 0xff,
-	0x84, 0x63, 0xc0, 0xab, 0x8f, 0x80, 0x47, 0x2b, 0x36, 0x2b, 0x4d, 0x0d, 0xaf, 0x73, 0x56, 0xeb,
-	0x40, 0xfb, 0xd8, 0x71, 0x0f, 0x8c, 0xf9, 0x82, 0x48, 0x17, 0x0b, 0x22, 0x5d, 0x2e, 0x88, 0xf4,
-	0x3d, 0x26, 0x68, 0x1e, 0x13, 0x74, 0x11, 0x13, 0x74, 0x19, 0x13, 0xf4, 0x37, 0x26, 0xe8, 0xc7,
-	0x3f, 0x22, 0x7d, 0x94, 0x75, 0x43, 0xd4, 0xf8, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x3a, 0x32, 0x3a,
-	0xd7, 0x1b, 0x05, 0x00, 0x00,
+var fileDescriptor_6f67d44e41cfe439 = []byte{
+	// 546 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xcf, 0x6e, 0xd3, 0x40,
+	0x10, 0xc6, 0xb3, 0x4d, 0x23, 0x25, 0x13, 0x25, 0x0d, 0x0b, 0x07, 0x13, 0x81, 0x5b, 0xa5, 0x12,
+	0x14, 0xa1, 0xd8, 0x6a, 0xb8, 0x44, 0x20, 0x0e, 0xad, 0x68, 0x29, 0x1c, 0x7a, 0x30, 0x08, 0x41,
+	0xa5, 0x80, 0x36, 0xc9, 0xc6, 0x5d, 0xc5, 0xb1, 0x23, 0xef, 0x3a, 0x52, 0x6e, 0x3c, 0x02, 0x0f,
+	0xc1, 0x15, 0x21, 0xf1, 0x14, 0x39, 0xf6, 0xd8, 0x53, 0x45, 0xcc, 0x8b, 0xa0, 0xf8, 0x4f, 0x6c,
+	0x27, 0x76, 0x2a, 0xb8, 0xed, 0x4e, 0xbe, 0xf9, 0xcd, 0xcc, 0xb7, 0x13, 0xc3, 0x19, 0x67, 0x3a,
+	0x57, 0x86, 0x6d, 0xae, 0x30, 0x4b, 0x35, 0xad, 0x3e, 0x6d, 0x0e, 0x28, 0x11, 0x8e, 0x4d, 0x9b,
+	0x7d, 0xc6, 0x7b, 0xd6, 0x84, 0xda, 0x53, 0x75, 0x3c, 0xd4, 0x55, 0x32, 0x66, 0x5c, 0x35, 0x07,
+	0x7d, 0x75, 0x72, 0x48, 0x8c, 0xf1, 0x25, 0x39, 0x54, 0x75, 0x6a, 0x52, 0x9b, 0x08, 0xda, 0x57,
+	0xc6, 0xb6, 0x25, 0x2c, 0x5c, 0x0c, 0x7f, 0xa9, 0x37, 0x75, 0x26, 0x2e, 0x9d, 0xae, 0xd2, 0xb3,
+	0x46, 0xaa, 0x6e, 0xe9, 0x96, 0xea, 0x09, 0xba, 0xce, 0xc0, 0xbb, 0x79, 0x17, 0xef, 0xe4, 0x27,
+	0x36, 0x7e, 0x20, 0xb8, 0x7b, 0x24, 0x84, 0xcd, 0xba, 0x8e, 0xa0, 0xa7, 0x7e, 0xf5, 0x77, 0x54,
+	0xe0, 0x4f, 0x50, 0xa4, 0x06, 0x1d, 0x51, 0x53, 0x70, 0x09, 0xed, 0xe5, 0x0f, 0xca, 0xad, 0xa7,
+	0x4a, 0x58, 0x43, 0x49, 0x49, 0x50, 0x4e, 0x02, 0xf5, 0x89, 0x29, 0xec, 0xe9, 0x71, 0x6d, 0x76,
+	0xb3, 0x9b, 0x73, 0x6f, 0x76, 0x8b, 0x61, 0x58, 0x5b, 0xe2, 0xea, 0x2f, 0xa0, 0x92, 0x10, 0xe3,
+	0x1a, 0xe4, 0x87, 0x74, 0x2a, 0xa1, 0x3d, 0x74, 0x50, 0xd2, 0x16, 0x47, 0x7c, 0x0f, 0x0a, 0x13,
+	0x62, 0x38, 0x54, 0xda, 0xf2, 0x62, 0xfe, 0xe5, 0xf9, 0x56, 0x1b, 0x35, 0xbe, 0x6f, 0x43, 0xf5,
+	0x95, 0x35, 0x22, 0xcc, 0x0c, 0x6a, 0x73, 0x7c, 0x06, 0x85, 0x81, 0x41, 0x74, 0x2e, 0x6d, 0x79,
+	0x7d, 0xee, 0x47, 0x7d, 0x26, 0x85, 0xca, 0xe9, 0x42, 0xe5, 0xf7, 0x57, 0x09, 0xfa, 0x2b, 0x78,
+	0x31, 0xcd, 0x07, 0xe0, 0x2f, 0x50, 0x9e, 0x90, 0x70, 0x36, 0x2e, 0xe5, 0x3d, 0xde, 0x93, 0x4c,
+	0xde, 0x87, 0x48, 0xeb, 0x53, 0x71, 0x40, 0x85, 0xa5, 0x41, 0x5c, 0x8b, 0x13, 0xf1, 0x47, 0x28,
+	0x31, 0x93, 0x0b, 0x62, 0xf6, 0x28, 0x97, 0xb6, 0x3d, 0xfc, 0xe3, 0x4c, 0xfc, 0x9b, 0x50, 0xe9,
+	0xc3, 0xef, 0x04, 0xf0, 0xd2, 0x32, 0xae, 0x45, 0xb0, 0xba, 0x06, 0x10, 0x8d, 0x97, 0xe2, 0xa8,
+	0x12, 0x77, 0xb4, 0xdc, 0x92, 0xa2, 0xaa, 0x8b, 0xb4, 0xe8, 0x1d, 0x63, 0x5e, 0xd7, 0x3b, 0x50,
+	0x5b, 0x1d, 0x31, 0x85, 0xfc, 0x2c, 0x49, 0x7e, 0xb8, 0x71, 0x4d, 0xe2, 0xf8, 0x0b, 0xa8, 0x26,
+	0x47, 0x4c, 0x81, 0xb7, 0x92, 0xf0, 0x07, 0x11, 0x3c, 0x4c, 0x4d, 0x65, 0x37, 0x7e, 0x21, 0xa8,
+	0x26, 0x07, 0xc3, 0xef, 0xd7, 0x36, 0xfa, 0x51, 0x96, 0x09, 0xff, 0xb0, 0xcc, 0x6f, 0x6f, 0x5f,
+	0xe6, 0xfd, 0xe4, 0x0c, 0x95, 0xa8, 0xea, 0x39, 0x33, 0xe2, 0x4d, 0xff, 0x44, 0xb0, 0xb3, 0x32,
+	0x16, 0xee, 0x00, 0xc4, 0x36, 0x12, 0xad, 0x6e, 0xe4, 0x8a, 0x3c, 0xb2, 0x7c, 0xc3, 0x46, 0xc6,
+	0x80, 0xf5, 0x97, 0xb0, 0x73, 0x74, 0xeb, 0x0b, 0x67, 0xff, 0x1b, 0x3b, 0x80, 0xd7, 0xdf, 0x01,
+	0xbf, 0x5e, 0x73, 0xfa, 0x7e, 0x66, 0xc7, 0x9b, 0xcc, 0x6d, 0x14, 0x20, 0x7f, 0xce, 0x8c, 0xe3,
+	0xcf, 0xb3, 0xb9, 0x9c, 0xbb, 0x9a, 0xcb, 0xb9, 0xeb, 0xb9, 0x9c, 0xfb, 0xea, 0xca, 0x68, 0xe6,
+	0xca, 0xe8, 0xca, 0x95, 0xd1, 0xb5, 0x2b, 0xa3, 0xdf, 0xae, 0x8c, 0xbe, 0xfd, 0x91, 0x73, 0x17,
+	0xed, 0xff, 0xfd, 0x98, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x75, 0x9e, 0xef, 0x0b, 0x87, 0x05,
+	0x00, 0x00,
 }
 
 func (m *AttributeFeatureSet) Marshal() (dAtA []byte, err error) {
@@ -357,7 +362,7 @@ func (m *DomainFeatures) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 			dAtA[i] = 0xa
 			i = encodeVarintGenerated(dAtA, i, uint64(baseI-i))
 			i--
-			dAtA[i] = 0x1a
+			dAtA[i] = 0x22
 		}
 	}
 	if len(m.Attributes) > 0 {
@@ -386,7 +391,7 @@ func (m *DomainFeatures) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 			dAtA[i] = 0xa
 			i = encodeVarintGenerated(dAtA, i, uint64(baseI-i))
 			i--
-			dAtA[i] = 0x12
+			dAtA[i] = 0x1a
 		}
 	}
 	if len(m.Flags) > 0 {
@@ -415,7 +420,7 @@ func (m *DomainFeatures) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 			dAtA[i] = 0xa
 			i = encodeVarintGenerated(dAtA, i, uint64(baseI-i))
 			i--
-			dAtA[i] = 0xa
+			dAtA[i] = 0x12
 		}
 	}
 	return len(dAtA) - i, nil
@@ -1049,7 +1054,7 @@ func (m *DomainFeatures) Unmarshal(dAtA []byte) error {
 			return fmt.Errorf("proto: DomainFeatures: illegal tag %d (wire type %d)", fieldNum, wire)
 		}
 		switch fieldNum {
-		case 1:
+		case 2:
 			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field Flags", wireType)
 			}
@@ -1178,7 +1183,7 @@ func (m *DomainFeatures) Unmarshal(dAtA []byte) error {
 			}
 			m.Flags[mapkey] = *mapvalue
 			iNdEx = postIndex
-		case 2:
+		case 3:
 			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType)
 			}
@@ -1307,7 +1312,7 @@ func (m *DomainFeatures) Unmarshal(dAtA []byte) error {
 			}
 			m.Attributes[mapkey] = *mapvalue
 			iNdEx = postIndex
-		case 3:
+		case 4:
 			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field Instances", wireType)
 			}
diff --git a/pkg/api/feature/generated.proto b/pkg/apis/nfd/v1alpha1/generated.proto
similarity index 80%
rename from pkg/api/feature/generated.proto
rename to pkg/apis/nfd/v1alpha1/generated.proto
index 810414854..6cb1fc8e0 100644
--- a/pkg/api/feature/generated.proto
+++ b/pkg/apis/nfd/v1alpha1/generated.proto
@@ -19,41 +19,53 @@ limitations under the License.
 
 syntax = "proto2";
 
-package feature;
+package v1alpha1;
 
 // Package-wide variables from generator "generated".
-option go_package = "sigs.k8s.io/node-feature-discovery/pkg/api/feature";
+option go_package = "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1";
 
 // AttributeFeatureSet is a set of features having string value.
+//
+// +protobuf=true
 message AttributeFeatureSet {
   map<string, string> elements = 1;
 }
 
 // DomainFeatures is the collection of all discovered features of one domain.
+//
+// +protobuf=true
 message DomainFeatures {
-  map<string, FlagFeatureSet> flags = 1;
+  map<string, FlagFeatureSet> flags = 2;
 
-  map<string, AttributeFeatureSet> vattributes = 2;
+  map<string, AttributeFeatureSet> vattributes = 3;
 
-  map<string, InstanceFeatureSet> instances = 3;
+  map<string, InstanceFeatureSet> instances = 4;
 }
 
 // FlagFeatureSet is a set of simple features only containing names without values.
+//
+// +protobuf=true
 message FlagFeatureSet {
   map<string, Nil> elements = 1;
 }
 
 // InstanceFeature represents one instance of a complex features, e.g. a device.
+//
+// +protobuf=true
 message InstanceFeature {
   map<string, string> attributes = 1;
 }
 
 // InstanceFeatureSet is a set of features each of which is an instance having multiple attributes.
+//
+// +protobuf=true
 message InstanceFeatureSet {
   repeated InstanceFeature elements = 1;
 }
 
 // Nil is a dummy empty struct for protobuf compatibility
+//
+// +protobuf=true
 message Nil {
 }
 
diff --git a/pkg/apis/nfd/v1alpha1/rule.go b/pkg/apis/nfd/v1alpha1/rule.go
index 1ed930269..ab0f6f913 100644
--- a/pkg/apis/nfd/v1alpha1/rule.go
+++ b/pkg/apis/nfd/v1alpha1/rule.go
@@ -24,7 +24,6 @@ import (
 
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 )
 
@@ -36,7 +35,7 @@ type RuleOutput struct {
 }
 
 // Execute the rule against a set of input features.
-func (r *Rule) Execute(features feature.Features) (RuleOutput, error) {
+func (r *Rule) Execute(features Features) (RuleOutput, error) {
 	labels := make(map[string]string)
 	vars := make(map[string]string)
 
@@ -150,11 +149,11 @@ type matchedFeatures map[string]domainMatchedFeatures
 
 type domainMatchedFeatures map[string]interface{}
 
-func (e *MatchAnyElem) match(features map[string]*feature.DomainFeatures) (bool, matchedFeatures, error) {
+func (e *MatchAnyElem) match(features map[string]*DomainFeatures) (bool, matchedFeatures, error) {
 	return e.MatchFeatures.match(features)
 }
 
-func (m *FeatureMatcher) match(features map[string]*feature.DomainFeatures) (bool, matchedFeatures, error) {
+func (m *FeatureMatcher) match(features map[string]*DomainFeatures) (bool, matchedFeatures, error) {
 	matches := make(matchedFeatures, len(*m))
 
 	// Logical AND over the terms
diff --git a/pkg/apis/nfd/v1alpha1/types.go b/pkg/apis/nfd/v1alpha1/types.go
index 1e486768d..4c3606b2f 100644
--- a/pkg/apis/nfd/v1alpha1/types.go
+++ b/pkg/apis/nfd/v1alpha1/types.go
@@ -20,6 +20,53 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
+// Features is a collection of all features of the system, arranged by domain.
+//
+// +protobuf=true
+type Features map[string]*DomainFeatures
+
+// DomainFeatures is the collection of all discovered features of one domain.
+//
+// +protobuf=true
+type DomainFeatures struct {
+	Flags      map[string]FlagFeatureSet      `json:"flags" protobuf:"bytes,2,rep,name=flags"`
+	Attributes map[string]AttributeFeatureSet `json:"attributes" protobuf:"bytes,3,rep,name=vattributes"`
+	Instances  map[string]InstanceFeatureSet  `json:"instances" protobuf:"bytes,4,rep,name=instances"`
+}
+
+// FlagFeatureSet is a set of simple features only containing names without values.
+//
+// +protobuf=true
+type FlagFeatureSet struct {
+	Elements map[string]Nil `json:"elements" protobuf:"bytes,1,rep,name=elements"`
+}
+
+// AttributeFeatureSet is a set of features having string value.
+//
+// +protobuf=true
+type AttributeFeatureSet struct {
+	Elements map[string]string `json:"elements" protobuf:"bytes,1,rep,name=elements"`
+}
+
+// InstanceFeatureSet is a set of features each of which is an instance having multiple attributes.
+//
+// +protobuf=true
+type InstanceFeatureSet struct {
+	Elements []InstanceFeature `json:"elements" protobuf:"bytes,1,rep,name=elements"`
+}
+
+// InstanceFeature represents one instance of a complex features, e.g. a device.
+//
+// +protobuf=true
+type InstanceFeature struct {
+	Attributes map[string]string `json:"attributes" protobuf:"bytes,1,rep,name=attributes"`
+}
+
+// Nil is a dummy empty struct for protobuf compatibility
+//
+// +protobuf=true
+type Nil struct{}
+
 // NodeFeatureRuleList contains a list of NodeFeatureRule objects.
 // +kubebuilder:object:root=true
 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
diff --git a/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go
index ff8f19f12..fb932ba67 100644
--- a/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/nfd/v1alpha1/zz_generated.deepcopy.go
@@ -9,6 +9,64 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 )
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AttributeFeatureSet) DeepCopyInto(out *AttributeFeatureSet) {
+	*out = *in
+	if in.Elements != nil {
+		in, out := &in.Elements, &out.Elements
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AttributeFeatureSet.
+func (in *AttributeFeatureSet) DeepCopy() *AttributeFeatureSet {
+	if in == nil {
+		return nil
+	}
+	out := new(AttributeFeatureSet)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *DomainFeatures) DeepCopyInto(out *DomainFeatures) {
+	*out = *in
+	if in.Flags != nil {
+		in, out := &in.Flags, &out.Flags
+		*out = make(map[string]FlagFeatureSet, len(*in))
+		for key, val := range *in {
+			(*out)[key] = *val.DeepCopy()
+		}
+	}
+	if in.Attributes != nil {
+		in, out := &in.Attributes, &out.Attributes
+		*out = make(map[string]AttributeFeatureSet, len(*in))
+		for key, val := range *in {
+			(*out)[key] = *val.DeepCopy()
+		}
+	}
+	if in.Instances != nil {
+		in, out := &in.Instances, &out.Instances
+		*out = make(map[string]InstanceFeatureSet, len(*in))
+		for key, val := range *in {
+			(*out)[key] = *val.DeepCopy()
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DomainFeatures.
+func (in *DomainFeatures) DeepCopy() *DomainFeatures {
+	if in == nil {
+		return nil
+	}
+	out := new(DomainFeatures)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in FeatureMatcher) DeepCopyInto(out *FeatureMatcher) {
 	{
@@ -60,6 +118,101 @@ func (in *FeatureMatcherTerm) DeepCopy() *FeatureMatcherTerm {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in Features) DeepCopyInto(out *Features) {
+	{
+		in := &in
+		*out = make(Features, len(*in))
+		for key, val := range *in {
+			var outVal *DomainFeatures
+			if val == nil {
+				(*out)[key] = nil
+			} else {
+				in, out := &val, &outVal
+				*out = new(DomainFeatures)
+				(*in).DeepCopyInto(*out)
+			}
+			(*out)[key] = outVal
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Features.
+func (in Features) DeepCopy() Features {
+	if in == nil {
+		return nil
+	}
+	out := new(Features)
+	in.DeepCopyInto(out)
+	return *out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *FlagFeatureSet) DeepCopyInto(out *FlagFeatureSet) {
+	*out = *in
+	if in.Elements != nil {
+		in, out := &in.Elements, &out.Elements
+		*out = make(map[string]Nil, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlagFeatureSet.
+func (in *FlagFeatureSet) DeepCopy() *FlagFeatureSet {
+	if in == nil {
+		return nil
+	}
+	out := new(FlagFeatureSet)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *InstanceFeature) DeepCopyInto(out *InstanceFeature) {
+	*out = *in
+	if in.Attributes != nil {
+		in, out := &in.Attributes, &out.Attributes
+		*out = make(map[string]string, len(*in))
+		for key, val := range *in {
+			(*out)[key] = val
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceFeature.
+func (in *InstanceFeature) DeepCopy() *InstanceFeature {
+	if in == nil {
+		return nil
+	}
+	out := new(InstanceFeature)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *InstanceFeatureSet) DeepCopyInto(out *InstanceFeatureSet) {
+	*out = *in
+	if in.Elements != nil {
+		in, out := &in.Elements, &out.Elements
+		*out = make([]InstanceFeature, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InstanceFeatureSet.
+func (in *InstanceFeatureSet) DeepCopy() *InstanceFeatureSet {
+	if in == nil {
+		return nil
+	}
+	out := new(InstanceFeatureSet)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *MatchAnyElem) DeepCopyInto(out *MatchAnyElem) {
 	*out = *in
@@ -202,6 +355,21 @@ func (in *MatchedValue) DeepCopy() *MatchedValue {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Nil) DeepCopyInto(out *Nil) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Nil.
+func (in *Nil) DeepCopy() *Nil {
+	if in == nil {
+		return nil
+	}
+	out := new(Nil)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *NodeFeatureRule) DeepCopyInto(out *NodeFeatureRule) {
 	*out = *in
diff --git a/pkg/labeler/labeler.pb.go b/pkg/labeler/labeler.pb.go
index c167403ca..68b2d8141 100644
--- a/pkg/labeler/labeler.pb.go
+++ b/pkg/labeler/labeler.pb.go
@@ -30,7 +30,7 @@ import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
 	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
 	reflect "reflect"
-	feature "sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	v1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	sync "sync"
 )
 
@@ -50,10 +50,10 @@ type SetLabelsRequest struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	NfdVersion string                             `protobuf:"bytes,1,opt,name=nfd_version,json=nfdVersion,proto3" json:"nfd_version,omitempty"`
-	NodeName   string                             `protobuf:"bytes,2,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"`
-	Labels     map[string]string                  `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
-	Features   map[string]*feature.DomainFeatures `protobuf:"bytes,4,rep,name=features,proto3" json:"features,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	NfdVersion string                              `protobuf:"bytes,1,opt,name=nfd_version,json=nfdVersion,proto3" json:"nfd_version,omitempty"`
+	NodeName   string                              `protobuf:"bytes,2,opt,name=node_name,json=nodeName,proto3" json:"node_name,omitempty"`
+	Labels     map[string]string                   `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	Features   map[string]*v1alpha1.DomainFeatures `protobuf:"bytes,4,rep,name=features,proto3" json:"features,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 }
 
 func (x *SetLabelsRequest) Reset() {
@@ -109,7 +109,7 @@ func (x *SetLabelsRequest) GetLabels() map[string]string {
 	return nil
 }
 
-func (x *SetLabelsRequest) GetFeatures() map[string]*feature.DomainFeatures {
+func (x *SetLabelsRequest) GetFeatures() map[string]*v1alpha1.DomainFeatures {
 	if x != nil {
 		return x.Features
 	}
@@ -158,41 +158,42 @@ var File_labeler_proto protoreflect.FileDescriptor
 
 var file_labeler_proto_rawDesc = []byte{
 	0x0a, 0x0d, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
-	0x07, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x1a, 0x1f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70,
-	0x69, 0x2f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
-	0x74, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe5, 0x02, 0x0a, 0x10, 0x53, 0x65,
-	0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1f,
-	0x0a, 0x0b, 0x6e, 0x66, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x66, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
-	0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x06,
-	0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6c,
-	0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e,
-	0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x43, 0x0a, 0x08, 0x66,
-	0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e,
+	0x07, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x1a, 0x25, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70,
+	0x69, 0x73, 0x2f, 0x6e, 0x66, 0x64, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2f,
+	0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
+	0xe6, 0x02, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x66, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73,
+	0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x66, 0x64, 0x56, 0x65,
+	0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x6e, 0x6f, 0x64, 0x65, 0x5f, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x6f, 0x64, 0x65, 0x4e, 0x61,
+	0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03,
+	0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74,
+	0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61,
+	0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c,
+	0x73, 0x12, 0x43, 0x0a, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x04, 0x20,
+	0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65,
+	0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46,
+	0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x66, 0x65,
+	0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73,
+	0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
+	0x01, 0x1a, 0x55, 0x0a, 0x0d, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74,
+	0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x03, 0x6b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x2e, 0x44,
+	0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x05, 0x76,
+	0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x10, 0x0a, 0x0e, 0x53, 0x65, 0x74, 0x4c,
+	0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x32, 0x4c, 0x0a, 0x07, 0x4c, 0x61,
+	0x62, 0x65, 0x6c, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x09, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65,
+	0x6c, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74,
+	0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e,
 	0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c,
-	0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65,
-	0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73,
-	0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
-	0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
-	0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x54, 0x0a, 0x0d, 0x46,
-	0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
-	0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2d,
-	0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e,
-	0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x46, 0x65,
-	0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
-	0x01, 0x22, 0x10, 0x0a, 0x0e, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65,
-	0x70, 0x6c, 0x79, 0x32, 0x4c, 0x0a, 0x07, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x12, 0x41,
-	0x0a, 0x09, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x19, 0x2e, 0x6c, 0x61,
-	0x62, 0x65, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52,
-	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72,
-	0x2e, 0x53, 0x65, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22,
-	0x00, 0x42, 0x30, 0x5a, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x2e, 0x6b, 0x38, 0x73, 0x2e, 0x69, 0x6f,
-	0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2d, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x2d, 0x64, 0x69,
-	0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6c, 0x61, 0x62, 0x65,
-	0x6c, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x30, 0x5a, 0x2e, 0x73, 0x69, 0x67, 0x73,
+	0x2e, 0x6b, 0x38, 0x73, 0x2e, 0x69, 0x6f, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2d, 0x66, 0x65, 0x61,
+	0x74, 0x75, 0x72, 0x65, 0x2d, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x79, 0x2f, 0x70,
+	0x6b, 0x67, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x33,
 }
 
 var (
@@ -209,16 +210,16 @@ func file_labeler_proto_rawDescGZIP() []byte {
 
 var file_labeler_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
 var file_labeler_proto_goTypes = []interface{}{
-	(*SetLabelsRequest)(nil),       // 0: labeler.SetLabelsRequest
-	(*SetLabelsReply)(nil),         // 1: labeler.SetLabelsReply
-	nil,                            // 2: labeler.SetLabelsRequest.LabelsEntry
-	nil,                            // 3: labeler.SetLabelsRequest.FeaturesEntry
-	(*feature.DomainFeatures)(nil), // 4: feature.DomainFeatures
+	(*SetLabelsRequest)(nil),        // 0: labeler.SetLabelsRequest
+	(*SetLabelsReply)(nil),          // 1: labeler.SetLabelsReply
+	nil,                             // 2: labeler.SetLabelsRequest.LabelsEntry
+	nil,                             // 3: labeler.SetLabelsRequest.FeaturesEntry
+	(*v1alpha1.DomainFeatures)(nil), // 4: v1alpha1.DomainFeatures
 }
 var file_labeler_proto_depIdxs = []int32{
 	2, // 0: labeler.SetLabelsRequest.labels:type_name -> labeler.SetLabelsRequest.LabelsEntry
 	3, // 1: labeler.SetLabelsRequest.features:type_name -> labeler.SetLabelsRequest.FeaturesEntry
-	4, // 2: labeler.SetLabelsRequest.FeaturesEntry.value:type_name -> feature.DomainFeatures
+	4, // 2: labeler.SetLabelsRequest.FeaturesEntry.value:type_name -> v1alpha1.DomainFeatures
 	0, // 3: labeler.Labeler.SetLabels:input_type -> labeler.SetLabelsRequest
 	1, // 4: labeler.Labeler.SetLabels:output_type -> labeler.SetLabelsReply
 	4, // [4:5] is the sub-list for method output_type
diff --git a/pkg/labeler/labeler.proto b/pkg/labeler/labeler.proto
index 6448e6044..e0119103d 100644
--- a/pkg/labeler/labeler.proto
+++ b/pkg/labeler/labeler.proto
@@ -18,7 +18,7 @@ syntax = "proto3";
 
 option go_package = "sigs.k8s.io/node-feature-discovery/pkg/labeler";
 
-import "pkg/api/feature/generated.proto";
+import "pkg/apis/nfd/v1alpha1/generated.proto";
 
 package labeler;
 
@@ -30,7 +30,7 @@ message SetLabelsRequest {
     string nfd_version = 1;
     string node_name = 2;
     map<string, string> labels = 3;
-    map<string, feature.DomainFeatures> features = 4;
+    map<string, v1alpha1.DomainFeatures> features = 4;
 }
 
 message SetLabelsReply {
diff --git a/pkg/nfd-client/worker/nfd-worker.go b/pkg/nfd-client/worker/nfd-worker.go
index e80d954b6..f97fade42 100644
--- a/pkg/nfd-client/worker/nfd-worker.go
+++ b/pkg/nfd-client/worker/nfd-worker.go
@@ -31,7 +31,7 @@ import (
 	"k8s.io/klog/v2"
 	"sigs.k8s.io/yaml"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	pb "sigs.k8s.io/node-feature-discovery/pkg/labeler"
 	clientcommon "sigs.k8s.io/node-feature-discovery/pkg/nfd-client"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
@@ -533,8 +533,8 @@ func getFeatureLabels(source source.LabelSource, labelWhiteList regexp.Regexp) (
 }
 
 // getFeatures returns raw features from all feature sources
-func getFeatures() map[string]*feature.DomainFeatures {
-	features := make(map[string]*feature.DomainFeatures)
+func getFeatures() map[string]*nfdv1alpha1.DomainFeatures {
+	features := make(map[string]*nfdv1alpha1.DomainFeatures)
 
 	for name, src := range source.GetAllFeatureSources() {
 		features[name] = src.GetFeatures()
diff --git a/pkg/nfd-master/nfd-master.go b/pkg/nfd-master/nfd-master.go
index dcf094859..812aa3baf 100644
--- a/pkg/nfd-master/nfd-master.go
+++ b/pkg/nfd-master/nfd-master.go
@@ -43,7 +43,6 @@ import (
 	restclient "k8s.io/client-go/rest"
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
 	"sigs.k8s.io/node-feature-discovery/pkg/apihelper"
 	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	pb "sigs.k8s.io/node-feature-discovery/pkg/labeler"
@@ -523,8 +522,8 @@ func (m *nfdMaster) crLabels(r *pb.SetLabelsRequest) map[string]string {
 			}
 
 			// Feed back rule output to features map for subsequent rules to match
-			feature.InsertAttributeFeatures(r.Features, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Labels)
-			feature.InsertAttributeFeatures(r.Features, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Vars)
+			nfdv1alpha1.InsertAttributeFeatures(r.Features, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Labels)
+			nfdv1alpha1.InsertAttributeFeatures(r.Features, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Vars)
 		}
 	}
 
diff --git a/source/cpu/cpu.go b/source/cpu/cpu.go
index 62d14af30..b2db7d8e0 100644
--- a/source/cpu/cpu.go
+++ b/source/cpu/cpu.go
@@ -24,7 +24,7 @@ import (
 
 	"github.com/klauspost/cpuid/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils/hostpath"
 	"sigs.k8s.io/node-feature-discovery/source"
@@ -102,7 +102,7 @@ type keyFilter struct {
 type cpuSource struct {
 	config      *Config
 	cpuidFilter *keyFilter
-	features    *feature.DomainFeatures
+	features    *nfdv1alpha1.DomainFeatures
 }
 
 // Singleton source instance
@@ -197,20 +197,20 @@ func (s *cpuSource) GetLabels() (source.FeatureLabels, error) {
 
 // Discover method of the FeatureSource Interface
 func (s *cpuSource) Discover() error {
-	s.features = feature.NewDomainFeatures()
+	s.features = nfdv1alpha1.NewDomainFeatures()
 
 	// Detect CPUID
-	s.features.Flags[CpuidFeature] = feature.NewFlagFeatures(getCpuidFlags()...)
+	s.features.Flags[CpuidFeature] = nfdv1alpha1.NewFlagFeatures(getCpuidFlags()...)
 
 	// Detect CPU model
-	s.features.Attributes[Cpumodel] = feature.NewAttributeFeatures(getCPUModel())
+	s.features.Attributes[Cpumodel] = nfdv1alpha1.NewAttributeFeatures(getCPUModel())
 
 	// Detect cstate configuration
 	cstate, err := detectCstate()
 	if err != nil {
 		klog.Errorf("failed to detect cstate: %v", err)
 	} else {
-		s.features.Attributes[CstateFeature] = feature.NewAttributeFeatures(cstate)
+		s.features.Attributes[CstateFeature] = nfdv1alpha1.NewAttributeFeatures(cstate)
 	}
 
 	// Detect pstate features
@@ -218,33 +218,33 @@ func (s *cpuSource) Discover() error {
 	if err != nil {
 		klog.Error(err)
 	}
-	s.features.Attributes[PstateFeature] = feature.NewAttributeFeatures(pstate)
+	s.features.Attributes[PstateFeature] = nfdv1alpha1.NewAttributeFeatures(pstate)
 
 	// Detect RDT features
-	s.features.Flags[RdtFeature] = feature.NewFlagFeatures(discoverRDT()...)
+	s.features.Flags[RdtFeature] = nfdv1alpha1.NewFlagFeatures(discoverRDT()...)
 
 	// Detect SGX features
-	s.features.Attributes[SecurityFeature] = feature.NewAttributeFeatures(discoverSecurity())
+	s.features.Attributes[SecurityFeature] = nfdv1alpha1.NewAttributeFeatures(discoverSecurity())
 
 	// Detect SGX features
 	//
 	// DEPRECATED in v0.12: will be removed in the future
 	if val, ok := s.features.Attributes[SecurityFeature].Elements["sgx.enabled"]; ok {
-		s.features.Attributes[SgxFeature] = feature.NewAttributeFeatures(map[string]string{"enabled": val})
+		s.features.Attributes[SgxFeature] = nfdv1alpha1.NewAttributeFeatures(map[string]string{"enabled": val})
 	}
 
 	// Detect Secure Execution features
 	//
 	// DEPRECATED in v0.12: will be removed in the future
 	if val, ok := s.features.Attributes[SecurityFeature].Elements["se.enabled"]; ok {
-		s.features.Attributes[SeFeature] = feature.NewAttributeFeatures(map[string]string{"enabled": val})
+		s.features.Attributes[SeFeature] = nfdv1alpha1.NewAttributeFeatures(map[string]string{"enabled": val})
 	}
 
 	// Detect SST features
-	s.features.Attributes[SstFeature] = feature.NewAttributeFeatures(discoverSST())
+	s.features.Attributes[SstFeature] = nfdv1alpha1.NewAttributeFeatures(discoverSST())
 
 	// Detect hyper-threading
-	s.features.Attributes[TopologyFeature] = feature.NewAttributeFeatures(discoverTopology())
+	s.features.Attributes[TopologyFeature] = nfdv1alpha1.NewAttributeFeatures(discoverTopology())
 
 	utils.KlogDump(3, "discovered cpu features:", "  ", s.features)
 
@@ -252,9 +252,9 @@ func (s *cpuSource) Discover() error {
 }
 
 // GetFeatures method of the FeatureSource Interface
-func (s *cpuSource) GetFeatures() *feature.DomainFeatures {
+func (s *cpuSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
 	if s.features == nil {
-		s.features = feature.NewDomainFeatures()
+		s.features = nfdv1alpha1.NewDomainFeatures()
 	}
 	return s.features
 }
diff --git a/source/custom/custom.go b/source/custom/custom.go
index 9b2484e95..80e374060 100644
--- a/source/custom/custom.go
+++ b/source/custom/custom.go
@@ -25,7 +25,6 @@ import (
 	"k8s.io/klog/v2"
 	"sigs.k8s.io/yaml"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
 	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 	"sigs.k8s.io/node-feature-discovery/source"
@@ -108,7 +107,7 @@ func (s *customSource) Priority() int { return 10 }
 // GetLabels method of the LabelSource interface
 func (s *customSource) GetLabels() (source.FeatureLabels, error) {
 	// Get raw features from all sources
-	domainFeatures := make(map[string]*feature.DomainFeatures)
+	domainFeatures := make(map[string]*nfdv1alpha1.DomainFeatures)
 	for n, s := range source.GetAllFeatureSources() {
 		domainFeatures[n] = s.GetFeatures()
 	}
@@ -129,13 +128,13 @@ func (s *customSource) GetLabels() (source.FeatureLabels, error) {
 			labels[n] = v
 		}
 		// Feed back rule output to features map for subsequent rules to match
-		feature.InsertAttributeFeatures(domainFeatures, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Labels)
-		feature.InsertAttributeFeatures(domainFeatures, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Vars)
+		nfdv1alpha1.InsertAttributeFeatures(domainFeatures, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Labels)
+		nfdv1alpha1.InsertAttributeFeatures(domainFeatures, nfdv1alpha1.RuleBackrefDomain, nfdv1alpha1.RuleBackrefFeature, ruleOut.Vars)
 	}
 	return labels, nil
 }
 
-func (r *CustomRule) execute(features map[string]*feature.DomainFeatures) (nfdv1alpha1.RuleOutput, error) {
+func (r *CustomRule) execute(features map[string]*nfdv1alpha1.DomainFeatures) (nfdv1alpha1.RuleOutput, error) {
 	if r.LegacyRule != nil {
 		ruleOut, err := r.LegacyRule.execute(features)
 		if err != nil {
@@ -155,7 +154,7 @@ func (r *CustomRule) execute(features map[string]*feature.DomainFeatures) (nfdv1
 	return nfdv1alpha1.RuleOutput{}, fmt.Errorf("BUG: an empty rule, this really should not happen")
 }
 
-func (r *LegacyRule) execute(features map[string]*feature.DomainFeatures) (map[string]string, error) {
+func (r *LegacyRule) execute(features map[string]*nfdv1alpha1.DomainFeatures) (map[string]string, error) {
 	if len(r.MatchOn) > 0 {
 		// Logical OR over the legacy rules
 		matched := false
diff --git a/source/fake/fake.go b/source/fake/fake.go
index d1d71393c..9a155f6aa 100644
--- a/source/fake/fake.go
+++ b/source/fake/fake.go
@@ -19,7 +19,7 @@ package fake
 import (
 	"fmt"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 	"sigs.k8s.io/node-feature-discovery/source"
 )
@@ -84,7 +84,7 @@ func newDefaultConfig() *Config {
 // fakeSource implements the FeatureSource, LabelSource and ConfigurableSource interfaces.
 type fakeSource struct {
 	config   *Config
-	features *feature.DomainFeatures
+	features *nfdv1alpha1.DomainFeatures
 }
 
 // Singleton source instance
@@ -116,16 +116,16 @@ func (s *fakeSource) SetConfig(conf source.Config) {
 
 // Discover method of the FeatureSource interface
 func (s *fakeSource) Discover() error {
-	s.features = feature.NewDomainFeatures()
+	s.features = nfdv1alpha1.NewDomainFeatures()
 
-	s.features.Flags[FlagFeature] = feature.NewFlagFeatures(s.config.FlagFeatures...)
-	s.features.Attributes[AttributeFeature] = feature.NewAttributeFeatures(s.config.AttributeFeatures)
+	s.features.Flags[FlagFeature] = nfdv1alpha1.NewFlagFeatures(s.config.FlagFeatures...)
+	s.features.Attributes[AttributeFeature] = nfdv1alpha1.NewAttributeFeatures(s.config.AttributeFeatures)
 
-	instances := make([]feature.InstanceFeature, len(s.config.InstanceFeatures))
+	instances := make([]nfdv1alpha1.InstanceFeature, len(s.config.InstanceFeatures))
 	for i, instanceAttributes := range s.config.InstanceFeatures {
-		instances[i] = *feature.NewInstanceFeature(instanceAttributes)
+		instances[i] = *nfdv1alpha1.NewInstanceFeature(instanceAttributes)
 	}
-	s.features.Instances[InstanceFeature] = feature.NewInstanceFeatures(instances)
+	s.features.Instances[InstanceFeature] = nfdv1alpha1.NewInstanceFeatures(instances)
 
 	utils.KlogDump(3, "discovered fake features:", "  ", s.features)
 
@@ -133,9 +133,9 @@ func (s *fakeSource) Discover() error {
 }
 
 // GetFeatures method of the FeatureSource Interface.
-func (s *fakeSource) GetFeatures() *feature.DomainFeatures {
+func (s *fakeSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
 	if s.features == nil {
-		s.features = feature.NewDomainFeatures()
+		s.features = nfdv1alpha1.NewDomainFeatures()
 	}
 	return s.features
 }
diff --git a/source/kernel/kernel.go b/source/kernel/kernel.go
index f2299e240..a96041104 100644
--- a/source/kernel/kernel.go
+++ b/source/kernel/kernel.go
@@ -21,7 +21,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 	"sigs.k8s.io/node-feature-discovery/source"
 )
@@ -58,7 +58,7 @@ func newDefaultConfig() *Config {
 // kernelSource implements the FeatureSource, LabelSource and ConfigurableSource interfaces.
 type kernelSource struct {
 	config   *Config
-	features *feature.DomainFeatures
+	features *nfdv1alpha1.DomainFeatures
 	// legacyKconfig contains mangled kconfig values used for
 	// kernel.config-<flag> labels and legacy kConfig custom rules.
 	legacyKconfig map[string]string
@@ -117,13 +117,13 @@ func (s *kernelSource) GetLabels() (source.FeatureLabels, error) {
 
 // Discover method of the FeatureSource interface
 func (s *kernelSource) Discover() error {
-	s.features = feature.NewDomainFeatures()
+	s.features = nfdv1alpha1.NewDomainFeatures()
 
 	// Read kernel version
 	if version, err := parseVersion(); err != nil {
 		klog.Errorf("failed to get kernel version: %s", err)
 	} else {
-		s.features.Attributes[VersionFeature] = feature.NewAttributeFeatures(version)
+		s.features.Attributes[VersionFeature] = nfdv1alpha1.NewAttributeFeatures(version)
 	}
 
 	// Read kconfig
@@ -131,20 +131,20 @@ func (s *kernelSource) Discover() error {
 		s.legacyKconfig = nil
 		klog.Errorf("failed to read kconfig: %s", err)
 	} else {
-		s.features.Attributes[ConfigFeature] = feature.NewAttributeFeatures(realKconfig)
+		s.features.Attributes[ConfigFeature] = nfdv1alpha1.NewAttributeFeatures(realKconfig)
 		s.legacyKconfig = legacyKconfig
 	}
 
 	if kmods, err := getLoadedModules(); err != nil {
 		klog.Errorf("failed to get loaded kernel modules: %v", err)
 	} else {
-		s.features.Flags[LoadedModuleFeature] = feature.NewFlagFeatures(kmods...)
+		s.features.Flags[LoadedModuleFeature] = nfdv1alpha1.NewFlagFeatures(kmods...)
 	}
 
 	if selinux, err := SelinuxEnabled(); err != nil {
 		klog.Warning(err)
 	} else {
-		s.features.Attributes[SelinuxFeature] = feature.NewAttributeFeatures(nil)
+		s.features.Attributes[SelinuxFeature] = nfdv1alpha1.NewAttributeFeatures(nil)
 		s.features.Attributes[SelinuxFeature].Elements["enabled"] = strconv.FormatBool(selinux)
 	}
 
@@ -153,9 +153,9 @@ func (s *kernelSource) Discover() error {
 	return nil
 }
 
-func (s *kernelSource) GetFeatures() *feature.DomainFeatures {
+func (s *kernelSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
 	if s.features == nil {
-		s.features = feature.NewDomainFeatures()
+		s.features = nfdv1alpha1.NewDomainFeatures()
 	}
 	return s.features
 }
diff --git a/source/local/local.go b/source/local/local.go
index 99ce32339..2187d0b27 100644
--- a/source/local/local.go
+++ b/source/local/local.go
@@ -26,7 +26,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 	"sigs.k8s.io/node-feature-discovery/source"
 )
@@ -45,7 +45,7 @@ var (
 
 // localSource implements the FeatureSource and LabelSource interfaces.
 type localSource struct {
-	features *feature.DomainFeatures
+	features *nfdv1alpha1.DomainFeatures
 	config   *Config
 }
 
@@ -103,7 +103,7 @@ func newDefaultConfig() *Config {
 
 // Discover method of the FeatureSource interface
 func (s *localSource) Discover() error {
-	s.features = feature.NewDomainFeatures()
+	s.features = nfdv1alpha1.NewDomainFeatures()
 
 	featuresFromFiles, err := getFeaturesFromFiles()
 	if err != nil {
@@ -129,7 +129,7 @@ func (s *localSource) Discover() error {
 		}
 	}
 
-	s.features.Attributes[LabelFeature] = feature.NewAttributeFeatures(featuresFromFiles)
+	s.features.Attributes[LabelFeature] = nfdv1alpha1.NewAttributeFeatures(featuresFromFiles)
 
 	utils.KlogDump(3, "discovered local features:", "  ", s.features)
 
@@ -137,9 +137,9 @@ func (s *localSource) Discover() error {
 }
 
 // GetFeatures method of the FeatureSource Interface
-func (s *localSource) GetFeatures() *feature.DomainFeatures {
+func (s *localSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
 	if s.features == nil {
-		s.features = feature.NewDomainFeatures()
+		s.features = nfdv1alpha1.NewDomainFeatures()
 	}
 	return s.features
 }
diff --git a/source/memory/memory.go b/source/memory/memory.go
index 0155da214..c9390fd7c 100644
--- a/source/memory/memory.go
+++ b/source/memory/memory.go
@@ -25,7 +25,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils/hostpath"
 	"sigs.k8s.io/node-feature-discovery/source"
@@ -42,7 +42,7 @@ const NumaFeature = "numa"
 
 // memorySource implements the FeatureSource and LabelSource interfaces.
 type memorySource struct {
-	features *feature.DomainFeatures
+	features *nfdv1alpha1.DomainFeatures
 }
 
 // Singleton source instance
@@ -84,20 +84,20 @@ func (s *memorySource) GetLabels() (source.FeatureLabels, error) {
 
 // Discover method of the FeatureSource interface
 func (s *memorySource) Discover() error {
-	s.features = feature.NewDomainFeatures()
+	s.features = nfdv1alpha1.NewDomainFeatures()
 
 	// Detect NUMA
 	if numa, err := detectNuma(); err != nil {
 		klog.Errorf("failed to detect NUMA nodes: %v", err)
 	} else {
-		s.features.Attributes[NumaFeature] = feature.AttributeFeatureSet{Elements: numa}
+		s.features.Attributes[NumaFeature] = nfdv1alpha1.AttributeFeatureSet{Elements: numa}
 	}
 
 	// Detect NVDIMM
 	if nv, err := detectNv(); err != nil {
 		klog.Errorf("failed to detect nvdimm devices: %v", err)
 	} else {
-		s.features.Instances[NvFeature] = feature.InstanceFeatureSet{Elements: nv}
+		s.features.Instances[NvFeature] = nfdv1alpha1.InstanceFeatureSet{Elements: nv}
 	}
 
 	utils.KlogDump(3, "discovered memory features:", "  ", s.features)
@@ -106,9 +106,9 @@ func (s *memorySource) Discover() error {
 }
 
 // GetFeatures method of the FeatureSource Interface.
-func (s *memorySource) GetFeatures() *feature.DomainFeatures {
+func (s *memorySource) GetFeatures() *nfdv1alpha1.DomainFeatures {
 	if s.features == nil {
-		s.features = feature.NewDomainFeatures()
+		s.features = nfdv1alpha1.NewDomainFeatures()
 	}
 	return s.features
 }
@@ -129,9 +129,9 @@ func detectNuma() (map[string]string, error) {
 }
 
 // detectNv detects NVDIMM devices
-func detectNv() ([]feature.InstanceFeature, error) {
+func detectNv() ([]nfdv1alpha1.InstanceFeature, error) {
 	sysfsBasePath := hostpath.SysfsDir.Path("bus/nd/devices")
-	info := make([]feature.InstanceFeature, 0)
+	info := make([]nfdv1alpha1.InstanceFeature, 0)
 
 	devices, err := os.ReadDir(sysfsBasePath)
 	if os.IsNotExist(err) {
@@ -153,7 +153,7 @@ func detectNv() ([]feature.InstanceFeature, error) {
 // ndDevAttrs is the list of sysfs files (under each nd device) that we're trying to read
 var ndDevAttrs = []string{"devtype", "mode"}
 
-func readNdDeviceInfo(path string) feature.InstanceFeature {
+func readNdDeviceInfo(path string) nfdv1alpha1.InstanceFeature {
 	attrs := map[string]string{"name": filepath.Base(path)}
 	for _, attrName := range ndDevAttrs {
 		data, err := os.ReadFile(filepath.Join(path, attrName))
@@ -163,7 +163,7 @@ func readNdDeviceInfo(path string) feature.InstanceFeature {
 		}
 		attrs[attrName] = strings.TrimSpace(string(data))
 	}
-	return *feature.NewInstanceFeature(attrs)
+	return *nfdv1alpha1.NewInstanceFeature(attrs)
 }
 
 func init() {
diff --git a/source/network/network.go b/source/network/network.go
index 7a36150b8..c906c1d61 100644
--- a/source/network/network.go
+++ b/source/network/network.go
@@ -25,7 +25,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils/hostpath"
 	"sigs.k8s.io/node-feature-discovery/source"
@@ -40,7 +40,7 @@ const sysfsBaseDir = "class/net"
 
 // networkSource implements the FeatureSource and LabelSource interfaces.
 type networkSource struct {
-	features *feature.DomainFeatures
+	features *nfdv1alpha1.DomainFeatures
 }
 
 // Singleton source instance
@@ -91,13 +91,13 @@ func (s *networkSource) GetLabels() (source.FeatureLabels, error) {
 
 // Discover method of the FeatureSource interface.
 func (s *networkSource) Discover() error {
-	s.features = feature.NewDomainFeatures()
+	s.features = nfdv1alpha1.NewDomainFeatures()
 
 	devs, err := detectNetDevices()
 	if err != nil {
 		return fmt.Errorf("failed to detect network devices: %w", err)
 	}
-	s.features.Instances[DeviceFeature] = feature.InstanceFeatureSet{Elements: devs}
+	s.features.Instances[DeviceFeature] = nfdv1alpha1.InstanceFeatureSet{Elements: devs}
 
 	utils.KlogDump(3, "discovered network features:", "  ", s.features)
 
@@ -105,14 +105,14 @@ func (s *networkSource) Discover() error {
 }
 
 // GetFeatures method of the FeatureSource Interface.
-func (s *networkSource) GetFeatures() *feature.DomainFeatures {
+func (s *networkSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
 	if s.features == nil {
-		s.features = feature.NewDomainFeatures()
+		s.features = nfdv1alpha1.NewDomainFeatures()
 	}
 	return s.features
 }
 
-func detectNetDevices() ([]feature.InstanceFeature, error) {
+func detectNetDevices() ([]nfdv1alpha1.InstanceFeature, error) {
 	sysfsBasePath := hostpath.SysfsDir.Path(sysfsBaseDir)
 
 	ifaces, err := os.ReadDir(sysfsBasePath)
@@ -121,7 +121,7 @@ func detectNetDevices() ([]feature.InstanceFeature, error) {
 	}
 
 	// Iterate over devices
-	info := make([]feature.InstanceFeature, 0, len(ifaces))
+	info := make([]nfdv1alpha1.InstanceFeature, 0, len(ifaces))
 	for _, iface := range ifaces {
 		name := iface.Name()
 		if _, err := os.Stat(filepath.Join(sysfsBasePath, name, "device")); err == nil {
@@ -134,7 +134,7 @@ func detectNetDevices() ([]feature.InstanceFeature, error) {
 	return info, nil
 }
 
-func readIfaceInfo(path string) feature.InstanceFeature {
+func readIfaceInfo(path string) nfdv1alpha1.InstanceFeature {
 	attrs := map[string]string{"name": filepath.Base(path)}
 	for _, attrName := range ifaceAttrs {
 		data, err := os.ReadFile(filepath.Join(path, attrName))
@@ -158,7 +158,7 @@ func readIfaceInfo(path string) feature.InstanceFeature {
 		attrs[attrName] = strings.TrimSpace(string(data))
 	}
 
-	return *feature.NewInstanceFeature(attrs)
+	return *nfdv1alpha1.NewInstanceFeature(attrs)
 
 }
 
diff --git a/source/pci/pci.go b/source/pci/pci.go
index b7a0f58c4..93fd0bdcd 100644
--- a/source/pci/pci.go
+++ b/source/pci/pci.go
@@ -22,7 +22,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 	"sigs.k8s.io/node-feature-discovery/source"
 )
@@ -50,7 +50,7 @@ func newDefaultConfig() *Config {
 // pciSource implements the FeatureSource, LabelSource and ConfigurableSource interfaces.
 type pciSource struct {
 	config   *Config
-	features *feature.DomainFeatures
+	features *nfdv1alpha1.DomainFeatures
 }
 
 // Singleton source instance
@@ -140,13 +140,13 @@ func (s *pciSource) GetLabels() (source.FeatureLabels, error) {
 
 // Discover method of the FeatureSource interface
 func (s *pciSource) Discover() error {
-	s.features = feature.NewDomainFeatures()
+	s.features = nfdv1alpha1.NewDomainFeatures()
 
 	devs, err := detectPci()
 	if err != nil {
 		return fmt.Errorf("failed to detect PCI devices: %s", err.Error())
 	}
-	s.features.Instances[DeviceFeature] = feature.NewInstanceFeatures(devs)
+	s.features.Instances[DeviceFeature] = nfdv1alpha1.NewInstanceFeatures(devs)
 
 	utils.KlogDump(3, "discovered pci features:", "  ", s.features)
 
@@ -154,9 +154,9 @@ func (s *pciSource) Discover() error {
 }
 
 // GetFeatures method of the FeatureSource Interface
-func (s *pciSource) GetFeatures() *feature.DomainFeatures {
+func (s *pciSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
 	if s.features == nil {
-		s.features = feature.NewDomainFeatures()
+		s.features = nfdv1alpha1.NewDomainFeatures()
 	}
 	return s.features
 }
diff --git a/source/pci/utils.go b/source/pci/utils.go
index 0c7b1af72..d9a370217 100644
--- a/source/pci/utils.go
+++ b/source/pci/utils.go
@@ -24,7 +24,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils/hostpath"
 )
 
@@ -50,7 +50,7 @@ func readSinglePciAttribute(devPath string, attrName string) (string, error) {
 }
 
 // Read information of one PCI device
-func readPciDevInfo(devPath string) (*feature.InstanceFeature, error) {
+func readPciDevInfo(devPath string) (*nfdv1alpha1.InstanceFeature, error) {
 	attrs := make(map[string]string)
 	for _, attr := range mandatoryDevAttrs {
 		attrVal, err := readSinglePciAttribute(devPath, attr)
@@ -65,12 +65,12 @@ func readPciDevInfo(devPath string) (*feature.InstanceFeature, error) {
 			attrs[attr] = attrVal
 		}
 	}
-	return feature.NewInstanceFeature(attrs), nil
+	return nfdv1alpha1.NewInstanceFeature(attrs), nil
 }
 
 // detectPci detects available PCI devices and retrieves their device attributes.
 // An error is returned if reading any of the mandatory attributes fails.
-func detectPci() ([]feature.InstanceFeature, error) {
+func detectPci() ([]nfdv1alpha1.InstanceFeature, error) {
 	sysfsBasePath := hostpath.SysfsDir.Path("bus/pci/devices")
 
 	devices, err := os.ReadDir(sysfsBasePath)
@@ -79,7 +79,7 @@ func detectPci() ([]feature.InstanceFeature, error) {
 	}
 
 	// Iterate over devices
-	devInfo := make([]feature.InstanceFeature, 0, len(devices))
+	devInfo := make([]nfdv1alpha1.InstanceFeature, 0, len(devices))
 	for _, device := range devices {
 		info, err := readPciDevInfo(filepath.Join(sysfsBasePath, device.Name()))
 		if err != nil {
diff --git a/source/source.go b/source/source.go
index 44a725ba8..2f0eb6dc8 100644
--- a/source/source.go
+++ b/source/source.go
@@ -21,7 +21,7 @@ package source
 import (
 	"fmt"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 )
 
 // Source is the base interface for all other source interfaces
@@ -38,7 +38,7 @@ type FeatureSource interface {
 	Discover() error
 
 	// GetFeatures returns discovered features in raw form
-	GetFeatures() *feature.DomainFeatures
+	GetFeatures() *nfdv1alpha1.DomainFeatures
 }
 
 // LabelSource represents a source of node feature labels
diff --git a/source/storage/storage.go b/source/storage/storage.go
index e04a8e361..e0b107b43 100644
--- a/source/storage/storage.go
+++ b/source/storage/storage.go
@@ -24,7 +24,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils/hostpath"
 	"sigs.k8s.io/node-feature-discovery/source"
@@ -37,7 +37,7 @@ const BlockFeature = "block"
 
 // storageSource implements the FeatureSource and LabelSource interfaces.
 type storageSource struct {
-	features *feature.DomainFeatures
+	features *nfdv1alpha1.DomainFeatures
 }
 
 // Singleton source instance
@@ -73,13 +73,13 @@ func (s *storageSource) GetLabels() (source.FeatureLabels, error) {
 
 // Discover method of the FeatureSource interface
 func (s *storageSource) Discover() error {
-	s.features = feature.NewDomainFeatures()
+	s.features = nfdv1alpha1.NewDomainFeatures()
 
 	devs, err := detectBlock()
 	if err != nil {
 		return fmt.Errorf("failed to detect block devices: %w", err)
 	}
-	s.features.Instances[BlockFeature] = feature.InstanceFeatureSet{Elements: devs}
+	s.features.Instances[BlockFeature] = nfdv1alpha1.InstanceFeatureSet{Elements: devs}
 
 	utils.KlogDump(3, "discovered storage features:", "  ", s.features)
 
@@ -87,14 +87,14 @@ func (s *storageSource) Discover() error {
 }
 
 // GetFeatures method of the FeatureSource Interface.
-func (s *storageSource) GetFeatures() *feature.DomainFeatures {
+func (s *storageSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
 	if s.features == nil {
-		s.features = feature.NewDomainFeatures()
+		s.features = nfdv1alpha1.NewDomainFeatures()
 	}
 	return s.features
 }
 
-func detectBlock() ([]feature.InstanceFeature, error) {
+func detectBlock() ([]nfdv1alpha1.InstanceFeature, error) {
 	sysfsBasePath := hostpath.SysfsDir.Path("block")
 
 	blockdevices, err := os.ReadDir(sysfsBasePath)
@@ -103,7 +103,7 @@ func detectBlock() ([]feature.InstanceFeature, error) {
 	}
 
 	// Iterate over devices
-	info := make([]feature.InstanceFeature, 0, len(blockdevices))
+	info := make([]nfdv1alpha1.InstanceFeature, 0, len(blockdevices))
 	for _, device := range blockdevices {
 		info = append(info, *readBlockDevQueueInfo(filepath.Join(sysfsBasePath, device.Name())))
 	}
@@ -111,7 +111,7 @@ func detectBlock() ([]feature.InstanceFeature, error) {
 	return info, nil
 }
 
-func readBlockDevQueueInfo(path string) *feature.InstanceFeature {
+func readBlockDevQueueInfo(path string) *nfdv1alpha1.InstanceFeature {
 	attrs := map[string]string{"name": filepath.Base(path)}
 	for _, attrName := range queueAttrs {
 		data, err := os.ReadFile(filepath.Join(path, "queue", attrName))
@@ -121,7 +121,7 @@ func readBlockDevQueueInfo(path string) *feature.InstanceFeature {
 		}
 		attrs[attrName] = strings.TrimSpace(string(data))
 	}
-	return feature.NewInstanceFeature(attrs)
+	return nfdv1alpha1.NewInstanceFeature(attrs)
 }
 
 func init() {
diff --git a/source/system/system.go b/source/system/system.go
index 8f437bbd3..304c9ed74 100644
--- a/source/system/system.go
+++ b/source/system/system.go
@@ -24,7 +24,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils/hostpath"
 	"sigs.k8s.io/node-feature-discovery/source"
@@ -47,7 +47,7 @@ const (
 
 // systemSource implements the FeatureSource and LabelSource interfaces.
 type systemSource struct {
-	features *feature.DomainFeatures
+	features *nfdv1alpha1.DomainFeatures
 }
 
 // Singleton source instance
@@ -78,10 +78,10 @@ func (s *systemSource) GetLabels() (source.FeatureLabels, error) {
 
 // Discover method of the FeatureSource interface
 func (s *systemSource) Discover() error {
-	s.features = feature.NewDomainFeatures()
+	s.features = nfdv1alpha1.NewDomainFeatures()
 
 	// Get node name
-	s.features.Attributes[NameFeature] = feature.NewAttributeFeatures(nil)
+	s.features.Attributes[NameFeature] = nfdv1alpha1.NewAttributeFeatures(nil)
 	s.features.Attributes[NameFeature].Elements["nodename"] = os.Getenv("NODE_NAME")
 
 	// Get os-release information
@@ -89,7 +89,7 @@ func (s *systemSource) Discover() error {
 	if err != nil {
 		klog.Errorf("failed to get os-release: %s", err)
 	} else {
-		s.features.Attributes[OsReleaseFeature] = feature.NewAttributeFeatures(release)
+		s.features.Attributes[OsReleaseFeature] = nfdv1alpha1.NewAttributeFeatures(release)
 
 		if v, ok := release["VERSION_ID"]; ok {
 			versionComponents := splitVersion(v)
@@ -107,9 +107,9 @@ func (s *systemSource) Discover() error {
 }
 
 // GetFeatures method of the FeatureSource Interface
-func (s *systemSource) GetFeatures() *feature.DomainFeatures {
+func (s *systemSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
 	if s.features == nil {
-		s.features = feature.NewDomainFeatures()
+		s.features = nfdv1alpha1.NewDomainFeatures()
 	}
 	return s.features
 }
diff --git a/source/usb/usb.go b/source/usb/usb.go
index 200f3b236..fd8a10dbc 100644
--- a/source/usb/usb.go
+++ b/source/usb/usb.go
@@ -22,7 +22,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 	"sigs.k8s.io/node-feature-discovery/pkg/utils"
 	"sigs.k8s.io/node-feature-discovery/source"
 )
@@ -53,7 +53,7 @@ func defaultDeviceLabelFields() []string { return []string{"class", "vendor", "d
 // usbSource implements the LabelSource and ConfigurableSource interfaces.
 type usbSource struct {
 	config   *Config
-	features *feature.DomainFeatures
+	features *nfdv1alpha1.DomainFeatures
 }
 
 // Singleton source instance
@@ -139,13 +139,13 @@ func (s *usbSource) GetLabels() (source.FeatureLabels, error) {
 
 // Discover method of the FeatureSource interface
 func (s *usbSource) Discover() error {
-	s.features = feature.NewDomainFeatures()
+	s.features = nfdv1alpha1.NewDomainFeatures()
 
 	devs, err := detectUsb()
 	if err != nil {
 		return fmt.Errorf("failed to detect USB devices: %s", err.Error())
 	}
-	s.features.Instances[DeviceFeature] = feature.NewInstanceFeatures(devs)
+	s.features.Instances[DeviceFeature] = nfdv1alpha1.NewInstanceFeatures(devs)
 
 	utils.KlogDump(3, "discovered usb features:", "  ", s.features)
 
@@ -153,9 +153,9 @@ func (s *usbSource) Discover() error {
 }
 
 // GetFeatures method of the FeatureSource Interface
-func (s *usbSource) GetFeatures() *feature.DomainFeatures {
+func (s *usbSource) GetFeatures() *nfdv1alpha1.DomainFeatures {
 	if s.features == nil {
-		s.features = feature.NewDomainFeatures()
+		s.features = nfdv1alpha1.NewDomainFeatures()
 	}
 	return s.features
 }
diff --git a/source/usb/utils.go b/source/usb/utils.go
index 38a5dbe35..c7772f885 100644
--- a/source/usb/utils.go
+++ b/source/usb/utils.go
@@ -25,7 +25,7 @@ import (
 
 	"k8s.io/klog/v2"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
+	nfdv1alpha1 "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 )
 
 var devAttrs = []string{"class", "vendor", "device", "serial"}
@@ -57,8 +57,8 @@ func readSingleUsbAttribute(devPath string, attrName string) (string, error) {
 }
 
 // Read information of one USB device
-func readUsbDevInfo(devPath string) ([]feature.InstanceFeature, error) {
-	instances := make([]feature.InstanceFeature, 0)
+func readUsbDevInfo(devPath string) ([]nfdv1alpha1.InstanceFeature, error) {
+	instances := make([]nfdv1alpha1.InstanceFeature, 0)
 	attrs := make(map[string]string)
 
 	for _, attr := range devAttrs {
@@ -71,7 +71,7 @@ func readUsbDevInfo(devPath string) ([]feature.InstanceFeature, error) {
 	// USB devices encode their class information either at the device or the interface level. If the device class
 	// is set, return as-is.
 	if attrs["class"] != "00" {
-		instances = append(instances, *feature.NewInstanceFeature(attrs))
+		instances = append(instances, *nfdv1alpha1.NewInstanceFeature(attrs))
 	} else {
 		// Otherwise, if a 00 is presented at the device level, descend to the interface level.
 		interfaces, err := filepath.Glob(devPath + "/*/bInterfaceClass")
@@ -94,7 +94,7 @@ func readUsbDevInfo(devPath string) ([]feature.InstanceFeature, error) {
 			}
 			subdevAttrs["class"] = attrVal
 
-			instances = append(instances, *feature.NewInstanceFeature(subdevAttrs))
+			instances = append(instances, *nfdv1alpha1.NewInstanceFeature(subdevAttrs))
 		}
 	}
 
@@ -102,7 +102,7 @@ func readUsbDevInfo(devPath string) ([]feature.InstanceFeature, error) {
 }
 
 // detectUsb detects available USB devices and retrieves their device attributes.
-func detectUsb() ([]feature.InstanceFeature, error) {
+func detectUsb() ([]nfdv1alpha1.InstanceFeature, error) {
 	// Unlike PCI, the USB sysfs interface includes entries not just for
 	// devices. We work around this by globbing anything that includes a
 	// valid product ID.
@@ -113,7 +113,7 @@ func detectUsb() ([]feature.InstanceFeature, error) {
 	}
 
 	// Iterate over devices
-	devInfo := make([]feature.InstanceFeature, 0)
+	devInfo := make([]nfdv1alpha1.InstanceFeature, 0)
 	for _, devPath := range devPaths {
 		devs, err := readUsbDevInfo(filepath.Dir(devPath))
 		if err != nil {


Test patch:
diff --git a/pkg/apis/nfd/v1alpha1/expression_test.go b/pkg/apis/nfd/v1alpha1/expression_test.go
index 6dcd5f3e9..aeb5f3638 100644
--- a/pkg/apis/nfd/v1alpha1/expression_test.go
+++ b/pkg/apis/nfd/v1alpha1/expression_test.go
@@ -22,7 +22,6 @@ import (
 	"github.com/stretchr/testify/assert"
 	"sigs.k8s.io/yaml"
 
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
 	api "sigs.k8s.io/node-feature-discovery/pkg/apis/nfd/v1alpha1"
 )
 
@@ -182,7 +181,7 @@ func TestMatch(t *testing.T) {
 
 func TestMatchKeys(t *testing.T) {
 	type V = api.MatchValue
-	type I = map[string]feature.Nil
+	type I = map[string]api.Nil
 	type TC struct {
 		op     api.MatchOp
 		values V
@@ -290,7 +289,7 @@ func TestMatchValues(t *testing.T) {
 }
 
 func TestMESMatchKeys(t *testing.T) {
-	type I = map[string]feature.Nil
+	type I = map[string]api.Nil
 	type MK = api.MatchedKey
 	type O = []MK
 	type TC struct {
@@ -413,7 +412,7 @@ baz: { op: Gt, value: ["10"] }
 }
 
 func TestMESMatchInstances(t *testing.T) {
-	type I = feature.InstanceFeature
+	type I = api.InstanceFeature
 	type MI = api.MatchedInstance
 	type O = []MI
 	type A = map[string]string
diff --git a/pkg/apis/nfd/v1alpha1/rule_test.go b/pkg/apis/nfd/v1alpha1/rule_test.go
index 51cf8920e..b19c2b633 100644
--- a/pkg/apis/nfd/v1alpha1/rule_test.go
+++ b/pkg/apis/nfd/v1alpha1/rule_test.go
@@ -20,11 +20,10 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-	"sigs.k8s.io/node-feature-discovery/pkg/api/feature"
 )
 
 func TestRule(t *testing.T) {
-	f := map[string]*feature.DomainFeatures{}
+	f := map[string]*DomainFeatures{}
 	r1 := Rule{Labels: map[string]string{"label-1": "", "label-2": "true"}}
 	r2 := Rule{
 		Labels: map[string]string{"label-1": "label-val-1"},
@@ -48,7 +47,7 @@ func TestRule(t *testing.T) {
 	assert.Error(t, err, "matching against a missing domain should have returned an error")
 
 	// Test empty domain
-	d := feature.NewDomainFeatures()
+	d := NewDomainFeatures()
 	f["domain-1"] = d
 
 	m, err = r1.Execute(f)
@@ -60,9 +59,9 @@ func TestRule(t *testing.T) {
 	assert.Error(t, err, "matching against a missing feature type should have returned an error")
 
 	// Test empty feature sets
-	d.Flags["kf-1"] = feature.NewFlagFeatures()
-	d.Attributes["vf-1"] = feature.NewAttributeFeatures(nil)
-	d.Instances["if-1"] = feature.NewInstanceFeatures(nil)
+	d.Flags["kf-1"] = NewFlagFeatures()
+	d.Attributes["vf-1"] = NewAttributeFeatures(nil)
+	d.Instances["if-1"] = NewInstanceFeatures(nil)
 
 	m, err = r1.Execute(f)
 	assert.Nilf(t, err, "unexpected error: %v", err)
@@ -73,10 +72,10 @@ func TestRule(t *testing.T) {
 	assert.Nil(t, m.Labels, "unexpected match")
 
 	// Test non-empty feature sets
-	d.Flags["kf-1"].Elements["key-x"] = feature.Nil{}
+	d.Flags["kf-1"].Elements["key-x"] = Nil{}
 	d.Attributes["vf-1"].Elements["key-1"] = "val-x"
-	d.Instances["if-1"] = feature.NewInstanceFeatures([]feature.InstanceFeature{
-		*feature.NewInstanceFeature(map[string]string{"attr-1": "val-x"})})
+	d.Instances["if-1"] = NewInstanceFeatures([]InstanceFeature{
+		*NewInstanceFeature(map[string]string{"attr-1": "val-x"})})
 
 	m, err = r1.Execute(f)
 	assert.Nilf(t, err, "unexpected error: %v", err)
@@ -98,7 +97,7 @@ func TestRule(t *testing.T) {
 	assert.Nilf(t, err, "unexpected error: %v", err)
 	assert.Nil(t, m.Labels, "keys should not have matched")
 
-	d.Flags["kf-1"].Elements["key-1"] = feature.Nil{}
+	d.Flags["kf-1"].Elements["key-1"] = Nil{}
 	m, err = r2.Execute(f)
 	assert.Nilf(t, err, "unexpected error: %v", err)
 	assert.Equal(t, r2.Labels, m.Labels, "keys should have matched")
@@ -208,19 +207,19 @@ func TestRule(t *testing.T) {
 }
 
 func TestTemplating(t *testing.T) {
-	f := map[string]*feature.DomainFeatures{
-		"domain_1": {
-			Flags: map[string]feature.FlagFeatureSet{
-				"kf_1": {
-					Elements: map[string]feature.Nil{
+	f := map[string]*DomainFeatures{
+		"domain_1": &DomainFeatures{
+			Flags: map[string]FlagFeatureSet{
+				"kf_1": FlagFeatureSet{
+					Elements: map[string]Nil{
 						"key-a": {},
 						"key-b": {},
 						"key-c": {},
 					},
 				},
 			},
-			Attributes: map[string]feature.AttributeFeatureSet{
-				"vf_1": {
+			Attributes: map[string]AttributeFeatureSet{
+				"vf_1": AttributeFeatureSet{
 					Elements: map[string]string{
 						"key-1": "val-1",
 						"keu-2": "val-2",
@@ -228,9 +227,9 @@ func TestTemplating(t *testing.T) {
 					},
 				},
 			},
-			Instances: map[string]feature.InstanceFeatureSet{
-				"if_1": {
-					Elements: []feature.InstanceFeature{
+			Instances: map[string]InstanceFeatureSet{
+				"if_1": InstanceFeatureSet{
+					Elements: []InstanceFeature{
 						{
 							Attributes: map[string]string{
 								"attr-1": "1",