diff --git a/api/http/handler/kubernetes/dashboard.go b/api/http/handler/kubernetes/dashboard.go
new file mode 100644
index 000000000..bb4787bd3
--- /dev/null
+++ b/api/http/handler/kubernetes/dashboard.go
@@ -0,0 +1,37 @@
+package kubernetes
+
+import (
+	"net/http"
+
+	httperror "github.com/portainer/portainer/pkg/libhttp/error"
+	"github.com/portainer/portainer/pkg/libhttp/response"
+)
+
+// @id GetKubernetesDashboard
+// @summary Get the dashboard summary data
+// @description Get the dashboard summary data which is simply a count of a range of different commonly used kubernetes resources
+// @description **Access policy**: authenticated
+// @tags kubernetes
+// @security ApiKeyAuth
+// @security jwt
+// @accept json
+// @produce json
+// @param id path int true "Environment (Endpoint) identifier"
+// @success 200 {array} kubernetes.K8sDashboard "Success"
+// @failure 400 "Invalid request"
+// @failure 500 "Server error"
+// @router /kubernetes/{id}/dashboard [get]
+func (handler *Handler) getKubernetesDashboard(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
+
+	cli, httpErr := handler.getProxyKubeClient(r)
+	if httpErr != nil {
+		return httpErr
+	}
+
+	dashboard, err := cli.GetDashboard()
+	if err != nil {
+		return httperror.InternalServerError("Unable to retrieve dashboard data", err)
+	}
+
+	return response.JSON(w, dashboard)
+}
diff --git a/api/http/handler/kubernetes/handler.go b/api/http/handler/kubernetes/handler.go
index 9b429ada2..9951cbc52 100644
--- a/api/http/handler/kubernetes/handler.go
+++ b/api/http/handler/kubernetes/handler.go
@@ -52,6 +52,7 @@ func NewHandler(bouncer security.BouncerService, authorizationService *authoriza
 	endpointRouter.Use(kubeOnlyMiddleware)
 	endpointRouter.Use(h.kubeClientMiddleware)
 
+	endpointRouter.Handle("/dashboard", httperror.LoggerHandler(h.getKubernetesDashboard)).Methods(http.MethodGet)
 	endpointRouter.Handle("/nodes_limits", httperror.LoggerHandler(h.getKubernetesNodesLimits)).Methods(http.MethodGet)
 	endpointRouter.Handle("/max_resource_limits", httperror.LoggerHandler(h.getKubernetesMaxResourceLimits)).Methods(http.MethodGet)
 	endpointRouter.Handle("/metrics/nodes", httperror.LoggerHandler(h.getKubernetesMetricsForAllNodes)).Methods(http.MethodGet)
diff --git a/api/http/models/kubernetes/dashboard.go b/api/http/models/kubernetes/dashboard.go
new file mode 100644
index 000000000..544bac265
--- /dev/null
+++ b/api/http/models/kubernetes/dashboard.go
@@ -0,0 +1,13 @@
+package kubernetes
+
+type (
+	K8sDashboard struct {
+		NamespacesCount   int64 `json:"namespacesCount"`
+		ApplicationsCount int64 `json:"applicationsCount"`
+		ServicesCount     int64 `json:"servicesCount"`
+		IngressesCount    int64 `json:"ingressesCount"`
+		ConfigMapsCount   int64 `json:"configMapsCount"`
+		SecretsCount      int64 `json:"secretsCount"`
+		VolumesCount      int64 `json:"volumesCount"`
+	}
+)
diff --git a/api/internal/concurrent/concurrent.go b/api/internal/concurrent/concurrent.go
new file mode 100644
index 000000000..47b875b7f
--- /dev/null
+++ b/api/internal/concurrent/concurrent.go
@@ -0,0 +1,144 @@
+// Package concurrent provides utilities for running multiple functions concurrently in Go.
+// For example, many kubernetes calls can take a while to fulfill.  Oftentimes in Portainer
+// we need to get a list of objects from multiple kubernetes REST APIs. We can often call these
+// apis concurrently to speed up the response time.
+// This package provides a clean way to do just that.
+//
+// Examples:
+//   The ConfigMaps and Secrets function converted using concurrent.Run.
+/*
+
+// GetConfigMapsAndSecrets gets all the ConfigMaps AND all the Secrets for a
+// given namespace in a k8s endpoint. The result is a list of both config maps
+// and secrets. The IsSecret boolean property indicates if a given struct is a
+// secret or configmap.
+func (kcl *KubeClient) GetConfigMapsAndSecrets(namespace string) ([]models.K8sConfigMapOrSecret, error) {
+
+	// use closures to capture the current kube client and namespace by declaring wrapper functions
+	// that match the interface signature for concurrent.Func
+
+	listConfigMaps := func(ctx context.Context) (interface{}, error) {
+		return kcl.cli.CoreV1().ConfigMaps(namespace).List(context.Background(), meta.ListOptions{})
+	}
+
+	listSecrets := func(ctx context.Context) (interface{}, error) {
+		return kcl.cli.CoreV1().Secrets(namespace).List(context.Background(), meta.ListOptions{})
+	}
+
+	// run the functions concurrently and wait for results.  We can also pass in a context to cancel.
+	// e.g. Deadline timer.
+	results, err := concurrent.Run(context.TODO(), listConfigMaps, listSecrets)
+	if err != nil {
+		return nil, err
+	}
+
+	var configMapList *core.ConfigMapList
+	var secretList *core.SecretList
+	for _, r := range results {
+		switch v := r.Result.(type) {
+		case *core.ConfigMapList:
+			configMapList = v
+		case *core.SecretList:
+			secretList = v
+		}
+	}
+
+	// TODO: Applications
+	var combined []models.K8sConfigMapOrSecret
+	for _, m := range configMapList.Items {
+		var cm models.K8sConfigMapOrSecret
+		cm.UID = string(m.UID)
+		cm.Name = m.Name
+		cm.Namespace = m.Namespace
+		cm.Annotations = m.Annotations
+		cm.Data = m.Data
+		cm.CreationDate = m.CreationTimestamp.Time.UTC().Format(time.RFC3339)
+		combined = append(combined, cm)
+	}
+
+	for _, s := range secretList.Items {
+		var secret models.K8sConfigMapOrSecret
+		secret.UID = string(s.UID)
+		secret.Name = s.Name
+		secret.Namespace = s.Namespace
+		secret.Annotations = s.Annotations
+		secret.Data = msbToMss(s.Data)
+		secret.CreationDate = s.CreationTimestamp.Time.UTC().Format(time.RFC3339)
+		secret.IsSecret = true
+		secret.SecretType = string(s.Type)
+		combined = append(combined, secret)
+	}
+
+	return combined, nil
+}
+
+*/
+
+package concurrent
+
+import (
+	"context"
+	"sync"
+)
+
+// Result contains the result and any error returned from running a client task function
+type Result struct {
+	Result any   // the result of running the task function
+	Err    error // any error that occurred while running the task function
+}
+
+// Func is a function returns a result or error
+type Func func(ctx context.Context) (any, error)
+
+// Run runs a list of functions returns the results
+func Run(ctx context.Context, maxConcurrency int, tasks ...Func) ([]Result, error) {
+	var wg sync.WaitGroup
+	resultsChan := make(chan Result, len(tasks))
+	taskChan := make(chan Func, len(tasks))
+
+	localCtx, cancelCtx := context.WithCancel(ctx)
+	defer cancelCtx()
+
+	runTask := func() {
+		defer wg.Done()
+		for fn := range taskChan {
+			result, err := fn(localCtx)
+			resultsChan <- Result{Result: result, Err: err}
+		}
+	}
+
+	// Set maxConcurrency to the number of tasks if zero or negative
+	if maxConcurrency <= 0 {
+		maxConcurrency = len(tasks)
+	}
+
+	// Start worker goroutines
+	for i := 0; i < maxConcurrency; i++ {
+		wg.Add(1)
+		go runTask()
+	}
+
+	// Add tasks to the task channel
+	for _, fn := range tasks {
+		taskChan <- fn
+	}
+
+	// Close the task channel to signal workers to stop when all tasks are done
+	close(taskChan)
+
+	// Wait for all workers to complete
+	wg.Wait()
+	close(resultsChan)
+
+	// Collect the results and cancel on error
+	results := make([]Result, 0, len(tasks))
+	for r := range resultsChan {
+		if r.Err != nil {
+			cancelCtx()
+			return nil, r.Err
+		}
+		results = append(results, r)
+	}
+
+	return results, nil
+}
diff --git a/api/kubernetes/cli/applications.go b/api/kubernetes/cli/applications.go
new file mode 100644
index 000000000..875c4c779
--- /dev/null
+++ b/api/kubernetes/cli/applications.go
@@ -0,0 +1,154 @@
+package cli
+
+import (
+	"context"
+	"strings"
+
+	models "github.com/portainer/portainer/api/http/models/kubernetes"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+// GetApplications gets a list of kubernetes workloads (or applications) by kind.  If Kind is not specified, gets the all
+func (kcl *KubeClient) GetApplications(namespace, kind string) ([]models.K8sApplication, error) {
+	applicationList := []models.K8sApplication{}
+	listOpts := metav1.ListOptions{}
+
+	if kind == "" || strings.EqualFold(kind, "deployment") {
+		deployments, err := kcl.cli.AppsV1().Deployments(namespace).List(context.TODO(), listOpts)
+		if err != nil {
+			return nil, err
+		}
+
+		for _, d := range deployments.Items {
+			applicationList = append(applicationList, models.K8sApplication{
+				UID:       string(d.UID),
+				Name:      d.Name,
+				Namespace: d.Namespace,
+				Kind:      "Deployment",
+				Labels:    d.Labels,
+			})
+		}
+	}
+
+	if kind == "" || strings.EqualFold(kind, "statefulset") {
+		statefulSets, err := kcl.cli.AppsV1().StatefulSets(namespace).List(context.TODO(), listOpts)
+		if err != nil {
+			return nil, err
+		}
+
+		for _, s := range statefulSets.Items {
+			applicationList = append(applicationList, models.K8sApplication{
+				UID:       string(s.UID),
+				Name:      s.Name,
+				Namespace: s.Namespace,
+				Kind:      "StatefulSet",
+				Labels:    s.Labels,
+			})
+		}
+	}
+
+	if kind == "" || strings.EqualFold(kind, "daemonset") {
+		daemonSets, err := kcl.cli.AppsV1().DaemonSets(namespace).List(context.TODO(), listOpts)
+		if err != nil {
+			return nil, err
+		}
+
+		for _, d := range daemonSets.Items {
+			applicationList = append(applicationList, models.K8sApplication{
+				UID:       string(d.UID),
+				Name:      d.Name,
+				Namespace: d.Namespace,
+				Kind:      "DaemonSet",
+				Labels:    d.Labels,
+			})
+		}
+	}
+
+	if kind == "" || strings.EqualFold(kind, "nakedpods") {
+		pods, _ := kcl.cli.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{})
+		for _, pod := range pods.Items {
+			naked := false
+			if len(pod.OwnerReferences) == 0 {
+				naked = true
+			} else {
+				managed := false
+			loop:
+				for _, ownerRef := range pod.OwnerReferences {
+					switch ownerRef.Kind {
+					case "Deployment", "DaemonSet", "ReplicaSet":
+						managed = true
+						break loop
+					}
+				}
+
+				if !managed {
+					naked = true
+				}
+			}
+
+			if naked {
+				applicationList = append(applicationList, models.K8sApplication{
+					UID:       string(pod.UID),
+					Name:      pod.Name,
+					Namespace: pod.Namespace,
+					Kind:      "Pod",
+					Labels:    pod.Labels,
+				})
+			}
+		}
+	}
+
+	return applicationList, nil
+}
+
+// GetApplication gets a kubernetes workload (application) by kind and name.  If Kind is not specified, gets the all
+func (kcl *KubeClient) GetApplication(namespace, kind, name string) (models.K8sApplication, error) {
+
+	opts := metav1.GetOptions{}
+
+	switch strings.ToLower(kind) {
+	case "deployment":
+		d, err := kcl.cli.AppsV1().Deployments(namespace).Get(context.TODO(), name, opts)
+		if err != nil {
+			return models.K8sApplication{}, err
+		}
+
+		return models.K8sApplication{
+			UID:       string(d.UID),
+			Name:      d.Name,
+			Namespace: d.Namespace,
+			Kind:      "Deployment",
+			Labels:    d.Labels,
+		}, nil
+
+	case "statefulset":
+		s, err := kcl.cli.AppsV1().StatefulSets(namespace).Get(context.TODO(), name, opts)
+		if err != nil {
+			return models.K8sApplication{}, err
+		}
+
+		return models.K8sApplication{
+			UID:       string(s.UID),
+			Name:      s.Name,
+			Namespace: s.Namespace,
+			Kind:      "StatefulSet",
+			Labels:    s.Labels,
+		}, nil
+
+	case "daemonset":
+		d, err := kcl.cli.AppsV1().DaemonSets(namespace).Get(context.TODO(), name, opts)
+		if err != nil {
+			return models.K8sApplication{}, err
+		}
+
+		return models.K8sApplication{
+			UID:       string(d.UID),
+			Name:      d.Name,
+			Namespace: d.Namespace,
+			Kind:      "DaemonSet",
+			Labels:    d.Labels,
+		}, nil
+	}
+
+	return models.K8sApplication{}, nil
+}
diff --git a/api/kubernetes/cli/client.go b/api/kubernetes/cli/client.go
index 045575baf..8fd62c286 100644
--- a/api/kubernetes/cli/client.go
+++ b/api/kubernetes/cli/client.go
@@ -25,6 +25,8 @@ const (
 	DefaultKubeClientBurst = 100
 )
 
+const maxConcurrency = 30
+
 type (
 	// ClientFactory is used to create Kubernetes clients
 	ClientFactory struct {
@@ -46,6 +48,13 @@ type (
 	}
 )
 
+func NewKubeClientFromClientset(cli *kubernetes.Clientset) *KubeClient {
+	return &KubeClient{
+		cli:        cli,
+		instanceID: "",
+	}
+}
+
 // NewClientFactory returns a new instance of a ClientFactory
 func NewClientFactory(signatureService portainer.DigitalSignatureService, reverseTunnelService portainer.ReverseTunnelService, dataStore dataservices.DataStore, instanceID, addrHTTPS, userSessionTimeout string) (*ClientFactory, error) {
 	if userSessionTimeout == "" {
diff --git a/api/kubernetes/cli/dashboard.go b/api/kubernetes/cli/dashboard.go
new file mode 100644
index 000000000..c96910365
--- /dev/null
+++ b/api/kubernetes/cli/dashboard.go
@@ -0,0 +1,258 @@
+package cli
+
+import (
+	"context"
+
+	models "github.com/portainer/portainer/api/http/models/kubernetes"
+	"github.com/portainer/portainer/api/internal/concurrent"
+
+	"k8s.io/apimachinery/pkg/api/errors"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+func (kcl *KubeClient) GetDashboard() (models.K8sDashboard, error) {
+	dashboardData := models.K8sDashboard{}
+
+	// Get a list of all the namespaces first
+	namespaces, err := kcl.cli.CoreV1().Namespaces().List(context.TODO(), v1.ListOptions{})
+	if err != nil {
+		return dashboardData, err
+	}
+
+	getNamespaceCounts := func(namespace string) concurrent.Func {
+		return func(ctx context.Context) (any, error) {
+			data := models.K8sDashboard{}
+
+			// apps (deployments, statefulsets, daemonsets)
+			applicationCount, err := getApplicationsCount(ctx, kcl, namespace)
+			if err != nil {
+				// skip namespaces we're not allowed access to.  But don't return an error so that we
+				// can still count the other namespaces.  Returning an error here will stop concurrent.Run
+				if errors.IsForbidden(err) {
+					return nil, nil
+				}
+				return nil, err
+			}
+			data.ApplicationsCount = applicationCount
+
+			// services
+			serviceCount, err := getServicesCount(ctx, kcl, namespace)
+			if err != nil {
+				return nil, err
+			}
+			data.ServicesCount = serviceCount
+
+			// ingresses
+			ingressesCount, err := getIngressesCount(ctx, kcl, namespace)
+			if err != nil {
+				return nil, err
+			}
+			data.IngressesCount = ingressesCount
+
+			// configmaps
+			configMapCount, err := getConfigMapsCount(ctx, kcl, namespace)
+			if err != nil {
+				return nil, err
+			}
+			data.ConfigMapsCount = configMapCount
+
+			// secrets
+			secretsCount, err := getSecretsCount(ctx, kcl, namespace)
+			if err != nil {
+				return nil, err
+			}
+			data.SecretsCount = secretsCount
+
+			// volumes
+			volumesCount, err := getVolumesCount(ctx, kcl, namespace)
+			if err != nil {
+				return nil, err
+			}
+			data.VolumesCount = volumesCount
+
+			// count this namespace for the user
+			data.NamespacesCount = 1
+
+			return data, nil
+		}
+	}
+
+	dashboardTasks := make([]concurrent.Func, 0)
+	for _, ns := range namespaces.Items {
+		dashboardTasks = append(dashboardTasks, getNamespaceCounts(ns.Name))
+	}
+
+	// Fetch all the data for each namespace concurrently
+	results, err := concurrent.Run(context.TODO(), maxConcurrency, dashboardTasks...)
+	if err != nil {
+		return dashboardData, err
+	}
+
+	// Sum up the results
+	for i := range results {
+		data, _ := results[i].Result.(models.K8sDashboard)
+		dashboardData.NamespacesCount += data.NamespacesCount
+		dashboardData.ApplicationsCount += data.ApplicationsCount
+		dashboardData.ServicesCount += data.ServicesCount
+		dashboardData.IngressesCount += data.IngressesCount
+		dashboardData.ConfigMapsCount += data.ConfigMapsCount
+		dashboardData.SecretsCount += data.SecretsCount
+		dashboardData.VolumesCount += data.VolumesCount
+	}
+
+	return dashboardData, nil
+}
+
+// Get applications excluding nakedpods
+func getApplicationsCount(ctx context.Context, kcl *KubeClient, namespace string) (int64, error) {
+	options := v1.ListOptions{Limit: 1}
+	count := int64(0)
+
+	// deployments
+	deployments, err := kcl.cli.AppsV1().Deployments(namespace).List(ctx, options)
+	if err != nil {
+		return 0, err
+	}
+
+	if len(deployments.Items) > 0 {
+		count = 1 // first deployment
+		remainingItemsCount := deployments.GetRemainingItemCount()
+		if remainingItemsCount != nil {
+			count += *remainingItemsCount // add the remaining deployments if any
+		}
+	}
+
+	// StatefulSets
+	statefulSets, err := kcl.cli.AppsV1().StatefulSets(namespace).List(ctx, options)
+	if err != nil {
+		return 0, err
+	}
+
+	if len(statefulSets.Items) > 0 {
+		count += 1 // + first statefulset
+		remainingItemsCount := statefulSets.GetRemainingItemCount()
+		if remainingItemsCount != nil {
+			count += *remainingItemsCount // add the remaining statefulsets if any
+		}
+	}
+
+	// Daemonsets
+	daemonsets, err := kcl.cli.AppsV1().DaemonSets(namespace).List(ctx, options)
+	if err != nil {
+		return 0, err
+	}
+
+	if len(daemonsets.Items) > 0 {
+		count += 1 // + first daemonset
+		remainingItemsCount := daemonsets.GetRemainingItemCount()
+		if remainingItemsCount != nil {
+			count += *remainingItemsCount // add the remaining daemonsets if any
+		}
+	}
+
+	// + (naked pods)
+	nakedPods, err := kcl.GetApplications(namespace, "nakedpods")
+	if err != nil {
+		return 0, err
+	}
+
+	return count + int64(len(nakedPods)), nil
+}
+
+// Get the total count of services for the given namespace
+func getServicesCount(ctx context.Context, kcl *KubeClient, namespace string) (int64, error) {
+	options := v1.ListOptions{
+		Limit: 1,
+	}
+	var count int64 = 0
+	services, err := kcl.cli.CoreV1().Services(namespace).List(ctx, options)
+	if err != nil {
+		return 0, err
+	}
+
+	if len(services.Items) > 0 {
+		count = 1 // first service
+		remainingItemsCount := services.GetRemainingItemCount()
+		if remainingItemsCount != nil {
+			count += *remainingItemsCount // add the remaining services if any
+		}
+	}
+
+	return count, nil
+}
+
+// Get the total count of ingresses for the given namespace
+func getIngressesCount(ctx context.Context, kcl *KubeClient, namespace string) (int64, error) {
+	ingresses, err := kcl.cli.NetworkingV1().Ingresses(namespace).List(ctx, v1.ListOptions{Limit: 1})
+	if err != nil {
+		return 0, err
+	}
+
+	count := int64(0)
+	if len(ingresses.Items) > 0 {
+		count = 1 // first ingress
+		remainingItemsCount := ingresses.GetRemainingItemCount()
+		if remainingItemsCount != nil {
+			count += *remainingItemsCount // add the remaining ingresses if any
+		}
+	}
+
+	return count, nil
+}
+
+// Get the total count of configMaps for the given namespace
+func getConfigMapsCount(ctx context.Context, kcl *KubeClient, namespace string) (int64, error) {
+	configMaps, err := kcl.cli.CoreV1().ConfigMaps(namespace).List(ctx, v1.ListOptions{Limit: 1})
+	if err != nil {
+		return 0, err
+	}
+
+	count := int64(0)
+	if len(configMaps.Items) > 0 {
+		count = 1 // first configmap
+		remainingItemsCount := configMaps.GetRemainingItemCount()
+		if remainingItemsCount != nil {
+			count += *remainingItemsCount // add the remaining configmaps if any
+		}
+	}
+
+	return count, nil
+}
+
+// Get the total count of secrets for the given namespace
+func getSecretsCount(ctx context.Context, kcl *KubeClient, namespace string) (int64, error) {
+	secrets, err := kcl.cli.CoreV1().Secrets(namespace).List(ctx, v1.ListOptions{Limit: 1})
+	if err != nil {
+		return 0, err
+	}
+
+	count := int64(0)
+	if len(secrets.Items) > 0 {
+		count = 1 // first secret
+		remainingItemsCount := secrets.GetRemainingItemCount()
+		if remainingItemsCount != nil {
+			count += *remainingItemsCount // add the remaining secrets if any
+		}
+	}
+
+	return count, nil
+}
+
+// Get the total count of volumes for the given namespace
+func getVolumesCount(ctx context.Context, kcl *KubeClient, namespace string) (int64, error) {
+	volumes, err := kcl.cli.CoreV1().PersistentVolumeClaims(namespace).List(ctx, v1.ListOptions{Limit: 1})
+	if err != nil {
+		return 0, err
+	}
+
+	count := int64(0)
+	if len(volumes.Items) > 0 {
+		count = 1 // first volume
+		remainingItemsCount := volumes.GetRemainingItemCount()
+		if remainingItemsCount != nil {
+			count += *remainingItemsCount // add the remaining volumes if any
+		}
+	}
+
+	return count, nil
+}
diff --git a/api/portainer.go b/api/portainer.go
index 557f5da20..847d6b5e2 100644
--- a/api/portainer.go
+++ b/api/portainer.go
@@ -1505,6 +1505,8 @@ type (
 		DeleteNamespace(namespace string) error
 		GetConfigMapsAndSecrets(namespace string) ([]models.K8sConfigMapOrSecret, error)
 		GetIngressControllers() (models.K8sIngressControllers, error)
+		GetApplications(namespace, kind string) ([]models.K8sApplication, error)
+		GetApplication(namespace, kind, name string) (models.K8sApplication, error)
 		GetMetrics() (models.K8sMetrics, error)
 		GetStorage() ([]KubernetesStorageClassConfig, error)
 		CreateIngress(namespace string, info models.K8sIngressInfo, owner string) error
diff --git a/app/react/kubernetes/dashboard/DashboardView.tsx b/app/react/kubernetes/dashboard/DashboardView.tsx
index 169512a3d..486b2299a 100644
--- a/app/react/kubernetes/dashboard/DashboardView.tsx
+++ b/app/react/kubernetes/dashboard/DashboardView.tsx
@@ -8,47 +8,15 @@ import { DashboardGrid } from '@@/DashboardItem/DashboardGrid';
 import { DashboardItem } from '@@/DashboardItem/DashboardItem';
 import { PageHeader } from '@@/PageHeader';
 
-import { useApplicationsQuery } from '../applications/application.queries';
-import { usePVCsQuery } from '../volumes/usePVCsQuery';
-import { useServicesForCluster } from '../services/service';
-import { useIngresses } from '../ingresses/queries';
-import { useConfigMapsForCluster } from '../configs/configmap.service';
-import { useSecretsForCluster } from '../configs/secret.service';
-import { useNamespacesQuery } from '../namespaces/queries/useNamespacesQuery';
-
 import { EnvironmentInfo } from './EnvironmentInfo';
+import { useGetDashboardQuery } from './queries/getDashboardQuery';
 
 export function DashboardView() {
   const queryClient = useQueryClient();
   const environmentId = useEnvironmentId();
-  const { data: namespaces, ...namespacesQuery } =
-    useNamespacesQuery(environmentId);
-  const namespaceNames = namespaces && Object.keys(namespaces);
-  const { data: applications, ...applicationsQuery } = useApplicationsQuery(
-    environmentId,
-    namespaceNames
-  );
-  const { data: pvcs, ...pvcsQuery } = usePVCsQuery(
-    environmentId,
-    namespaceNames
-  );
-  const { data: services, ...servicesQuery } = useServicesForCluster(
-    environmentId,
-    namespaceNames,
-    { lookupApplications: false }
-  );
-  const { data: ingresses, ...ingressesQuery } = useIngresses(
-    environmentId,
-    namespaceNames
-  );
-  const { data: configMaps, ...configMapsQuery } = useConfigMapsForCluster(
-    environmentId,
-    namespaceNames
-  );
-  const { data: secrets, ...secretsQuery } = useSecretsForCluster(
-    environmentId,
-    namespaceNames
-  );
+  const dashboardQuery = useGetDashboardQuery(environmentId);
+
+  const dashboard = dashboardQuery.data;
 
   return (
     <>
@@ -64,42 +32,36 @@ export function DashboardView() {
         
         
           
           
           
           
           
           
           
+    ['environments', environmentId, 'dashboard'] as const,
+};
+
+export function useGetDashboardQuery(
+  environmentId: EnvironmentId,
+  options?: { autoRefreshRate?: number }
+) {
+  return useQuery(
+    queryKeys.list(environmentId),
+    async () => getDashboard(environmentId),
+    {
+      ...withError('Unable to get dashboard stats'),
+      refetchInterval() {
+        return options?.autoRefreshRate ?? false;
+      },
+    }
+  );
+}
+
+async function getDashboard(environmentId: EnvironmentId) {
+  try {
+    const { data: dashboard } = await axios.get(
+      `kubernetes/${environmentId}/dashboard`
+    );
+
+    return dashboard;
+  } catch (e) {
+    throw parseAxiosError(
+      e,
+      'Unable to get dashboard stats. Some counts may be inaccurate.'
+    );
+  }
+}
diff --git a/app/react/kubernetes/dashboard/types.ts b/app/react/kubernetes/dashboard/types.ts
new file mode 100644
index 000000000..165b2bd8f
--- /dev/null
+++ b/app/react/kubernetes/dashboard/types.ts
@@ -0,0 +1,9 @@
+export type K8sDashboard = {
+  namespacesCount: number;
+  applicationsCount: number;
+  servicesCount: number;
+  ingressesCount: number;
+  configMapsCount: number;
+  secretsCount: number;
+  volumesCount: number;
+};