diff --git a/metadata/report/nacos/report.go b/metadata/report/nacos/report.go
index 4333d52ac1069ad415e3b09c017df7e550ad3876..9dbec518220c3692257d29b1f01d78b0894f249e 100644
--- a/metadata/report/nacos/report.go
+++ b/metadata/report/nacos/report.go
@@ -20,16 +20,31 @@ package nacos
 import (
 	"encoding/json"
 	"net/url"
+)
 
+import (
 	"github.com/nacos-group/nacos-sdk-go/clients/config_client"
 	"github.com/nacos-group/nacos-sdk-go/vo"
 	perrors "github.com/pkg/errors"
+)
 
+import (
 	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/extension"
 	"github.com/apache/dubbo-go/common/logger"
 	"github.com/apache/dubbo-go/metadata/identifier"
+	"github.com/apache/dubbo-go/metadata/report"
+	"github.com/apache/dubbo-go/metadata/report/factory"
+	"github.com/apache/dubbo-go/remoting/nacos"
 )
 
+func init() {
+	ftry := &nacosMetadataReportFactory{}
+	extension.SetMetadataReportFactory("nacos", func() factory.MetadataReportFactory {
+		return ftry
+	})
+}
+
 // nacosMetadataReport is the implementation of MetadataReport based Nacos
 type nacosMetadataReport struct {
 	client config_client.IConfigClient
@@ -169,3 +184,15 @@ func (n *nacosMetadataReport) getConfig(param vo.ConfigParam) string {
 	}
 	return cfg
 }
+
+type nacosMetadataReportFactory struct {
+}
+
+func (n *nacosMetadataReportFactory) CreateMetadataReport(url *common.URL) report.MetadataReport {
+	client, err := nacos.NewNacosConfigClient(url)
+	if err != nil {
+		logger.Errorf("Could not create nacos metadata report. URL: %s", url.String())
+		return nil
+	}
+	return &nacosMetadataReport{client: client}
+}
diff --git a/metadata/report/nacos/report_test.go b/metadata/report/nacos/report_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..711e6281a295005501ad9384f6fc3433c2e2830d
--- /dev/null
+++ b/metadata/report/nacos/report_test.go
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 nacos
+
+import (
+	"strconv"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/metadata/identifier"
+	"github.com/apache/dubbo-go/metadata/report"
+)
+
+func TestNacosMetadataReport_CRUD(t *testing.T) {
+	rpt := newTestReport()
+	assert.NotNil(t, rpt)
+
+	providerMi := newMetadataIdentifier("server")
+	providerMeta := "provider"
+	err := rpt.StoreProviderMetadata(providerMi, providerMeta)
+
+	consumerMi := newMetadataIdentifier("client")
+	consumerMeta := "consumer"
+	err = rpt.StoreConsumerMetadata(consumerMi, consumerMeta)
+	assert.Nil(t, err)
+
+	serviceMi := newServiceMetadataIdentifier()
+	serviceUrl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+
+	err = rpt.SaveServiceMetadata(serviceMi, serviceUrl)
+	assert.Nil(t, err)
+
+	exportedUrls := rpt.GetExportedURLs(serviceMi)
+	assert.Equal(t, 1, len(exportedUrls))
+
+	subMi := newSubscribeMetadataIdentifier()
+	urlList := make([]common.URL, 0, 1)
+	urlList = append(urlList, serviceUrl)
+	err = rpt.SaveSubscribedData(subMi, urlList)
+	assert.Nil(t, err)
+
+	subscribeUrl := rpt.GetSubscribedURLs(subMi)
+	assert.Equal(t, 1, len(subscribeUrl))
+
+	err = rpt.RemoveServiceMetadata(serviceMi)
+	assert.Nil(t, err)
+
+}
+
+func newSubscribeMetadataIdentifier() *identifier.SubscriberMetadataIdentifier {
+	return &identifier.SubscriberMetadataIdentifier{
+		Revision:           "subscribe",
+		MetadataIdentifier: *newMetadataIdentifier("provider"),
+	}
+
+}
+
+func newServiceMetadataIdentifier() *identifier.ServiceMetadataIdentifier {
+	return &identifier.ServiceMetadataIdentifier{
+		Protocol: "nacos",
+		Revision: "a",
+		BaseMetadataIdentifier: identifier.BaseMetadataIdentifier{
+			ServiceInterface: "com.test.MyTest",
+			Version:          "1.0.0",
+			Group:            "test_group",
+			Side:             "service",
+		},
+	}
+}
+
+func newMetadataIdentifier(side string) *identifier.MetadataIdentifier {
+	return &identifier.MetadataIdentifier{
+		Application: "test",
+		BaseMetadataIdentifier: identifier.BaseMetadataIdentifier{
+			ServiceInterface: "com.test.MyTest",
+			Version:          "1.0.0",
+			Group:            "test_group",
+			Side:             side,
+		},
+	}
+}
+
+func TestNacosMetadataReportFactory_CreateMetadataReport(t *testing.T) {
+	res := newTestReport()
+	assert.NotNil(t, res)
+}
+
+func newTestReport() report.MetadataReport {
+	regurl, _ := common.NewURL("registry://console.nacos.io:80", common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)))
+	res := extension.GetMetadataReportFactory("nacos").CreateMetadataReport(&regurl)
+	return res
+}
diff --git a/registry/nacos/base_registry.go b/registry/nacos/base_registry.go
index 63f4999675470853d0f48d1a22b709efdc1c9d26..636ffc302ee30a58ea1b9160d498c3e4968556cb 100644
--- a/registry/nacos/base_registry.go
+++ b/registry/nacos/base_registry.go
@@ -18,22 +18,15 @@
 package nacos
 
 import (
-	"net"
-	"strconv"
-	"strings"
-	"time"
+	"github.com/apache/dubbo-go/remoting/nacos"
 )
 
 import (
-	"github.com/nacos-group/nacos-sdk-go/clients"
 	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
-	nacosConstant "github.com/nacos-group/nacos-sdk-go/common/constant"
-	perrors "github.com/pkg/errors"
 )
 
 import (
 	"github.com/apache/dubbo-go/common"
-	"github.com/apache/dubbo-go/common/constant"
 )
 
 // baseRegistry is the parent of both interface-level registry
@@ -45,11 +38,7 @@ type nacosBaseRegistry struct {
 
 // newBaseRegistry will create new instance
 func newBaseRegistry(url *common.URL) (nacosBaseRegistry, error) {
-	nacosConfig, err := getNacosConfig(url)
-	if err != nil {
-		return nacosBaseRegistry{}, err
-	}
-	client, err := clients.CreateNamingClient(nacosConfig)
+	client, err := nacos.NewNacosNamingClient(url)
 	if err != nil {
 		return nacosBaseRegistry{}, err
 	}
@@ -59,44 +48,3 @@ func newBaseRegistry(url *common.URL) (nacosBaseRegistry, error) {
 	}
 	return registry, nil
 }
-
-// getNacosConfig will return the nacos config
-func getNacosConfig(url *common.URL) (map[string]interface{}, error) {
-	if url == nil {
-		return nil, perrors.New("url is empty!")
-	}
-	if len(url.Location) == 0 {
-		return nil, perrors.New("url.location is empty!")
-	}
-	configMap := make(map[string]interface{}, 2)
-
-	addresses := strings.Split(url.Location, ",")
-	serverConfigs := make([]nacosConstant.ServerConfig, 0, len(addresses))
-	for _, addr := range addresses {
-		ip, portStr, err := net.SplitHostPort(addr)
-		if err != nil {
-			return nil, perrors.WithMessagef(err, "split [%s] ", addr)
-		}
-		port, _ := strconv.Atoi(portStr)
-		serverConfigs = append(serverConfigs, nacosConstant.ServerConfig{
-			IpAddr: ip,
-			Port:   uint64(port),
-		})
-	}
-	configMap["serverConfigs"] = serverConfigs
-
-	var clientConfig nacosConstant.ClientConfig
-	timeout, err := time.ParseDuration(url.GetParam(constant.REGISTRY_TIMEOUT_KEY, constant.DEFAULT_REG_TIMEOUT))
-	if err != nil {
-		return nil, err
-	}
-	clientConfig.TimeoutMs = uint64(timeout.Seconds() * 1000)
-	clientConfig.ListenInterval = 2 * clientConfig.TimeoutMs
-	clientConfig.CacheDir = url.GetParam(constant.NACOS_CACHE_DIR_KEY, "")
-	clientConfig.LogDir = url.GetParam(constant.NACOS_LOG_DIR_KEY, "")
-	clientConfig.Endpoint = url.GetParam(constant.NACOS_ENDPOINT, "")
-	clientConfig.NotLoadCacheAtStart = true
-	configMap["clientConfig"] = clientConfig
-
-	return configMap, nil
-}
diff --git a/remoting/nacos/builder.go b/remoting/nacos/builder.go
new file mode 100644
index 0000000000000000000000000000000000000000..bf89d4a7b97399054b500a9c6ec52d664d5d8799
--- /dev/null
+++ b/remoting/nacos/builder.go
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 nacos
+
+import (
+	"net"
+	"strconv"
+	"strings"
+	"time"
+)
+
+import (
+	"github.com/nacos-group/nacos-sdk-go/clients"
+	"github.com/nacos-group/nacos-sdk-go/clients/config_client"
+	"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
+	nacosConstant "github.com/nacos-group/nacos-sdk-go/common/constant"
+	perrors "github.com/pkg/errors"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+)
+
+func NewNacosNamingClient(url *common.URL) (naming_client.INamingClient, error) {
+	nacosConfig, err := getNacosConfig(url)
+	if err != nil {
+		return nil, err
+	}
+	return clients.CreateNamingClient(nacosConfig)
+}
+
+func NewNacosConfigClient(url *common.URL) (config_client.IConfigClient, error) {
+	nacosConfig, err := getNacosConfig(url)
+	if err != nil {
+		return nil, err
+	}
+	return clients.CreateConfigClient(nacosConfig)
+}
+
+// getNacosConfig will return the nacos config
+func getNacosConfig(url *common.URL) (map[string]interface{}, error) {
+	if url == nil {
+		return nil, perrors.New("url is empty!")
+	}
+	if len(url.Location) == 0 {
+		return nil, perrors.New("url.location is empty!")
+	}
+	configMap := make(map[string]interface{}, 2)
+
+	addresses := strings.Split(url.Location, ",")
+	serverConfigs := make([]nacosConstant.ServerConfig, 0, len(addresses))
+	for _, addr := range addresses {
+		ip, portStr, err := net.SplitHostPort(addr)
+		if err != nil {
+			return nil, perrors.WithMessagef(err, "split [%s] ", addr)
+		}
+		port, _ := strconv.Atoi(portStr)
+		serverConfigs = append(serverConfigs, nacosConstant.ServerConfig{
+			IpAddr: ip,
+			Port:   uint64(port),
+		})
+	}
+	configMap["serverConfigs"] = serverConfigs
+
+	var clientConfig nacosConstant.ClientConfig
+	timeout, err := time.ParseDuration(url.GetParam(constant.REGISTRY_TIMEOUT_KEY, constant.DEFAULT_REG_TIMEOUT))
+	if err != nil {
+		return nil, err
+	}
+	clientConfig.TimeoutMs = uint64(timeout.Seconds() * 1000)
+	clientConfig.ListenInterval = 2 * clientConfig.TimeoutMs
+	clientConfig.CacheDir = url.GetParam(constant.NACOS_CACHE_DIR_KEY, "")
+	clientConfig.LogDir = url.GetParam(constant.NACOS_LOG_DIR_KEY, "")
+	clientConfig.Endpoint = url.GetParam(constant.NACOS_ENDPOINT, "")
+	clientConfig.NotLoadCacheAtStart = true
+	configMap["clientConfig"] = clientConfig
+
+	return configMap, nil
+}