diff --git a/app/models/namespaces/traversal/linear_scopes.rb b/app/models/namespaces/traversal/linear_scopes.rb
index 0a4216e043a1e8492dccb3a41f1c987b5be0650f..f5c44171c4293e3c409faf8681ee5044dbb02d12 100644
--- a/app/models/namespaces/traversal/linear_scopes.rb
+++ b/app/models/namespaces/traversal/linear_scopes.rb
@@ -15,6 +15,13 @@ def as_ids
           select('namespaces.traversal_ids[array_length(namespaces.traversal_ids, 1)] AS id')
         end
 
+        def roots
+          return super unless use_traversal_ids_roots?
+
+          root_ids = all.select("#{quoted_table_name}.traversal_ids[1]").distinct
+          unscoped.where(id: root_ids)
+        end
+
         def self_and_ancestors(include_self: true, hierarchy_order: nil)
           return super unless use_traversal_ids_for_ancestor_scopes?
 
@@ -83,6 +90,11 @@ def use_traversal_ids?
           Feature.enabled?(:use_traversal_ids, default_enabled: :yaml)
         end
 
+        def use_traversal_ids_roots?
+          Feature.enabled?(:use_traversal_ids_roots, default_enabled: :yaml) &&
+          use_traversal_ids?
+        end
+
         def use_traversal_ids_for_ancestor_scopes?
           Feature.enabled?(:use_traversal_ids_for_ancestor_scopes, default_enabled: :yaml) &&
           use_traversal_ids?
diff --git a/app/models/namespaces/traversal/recursive_scopes.rb b/app/models/namespaces/traversal/recursive_scopes.rb
index 6659cefe095366806c74d6ef0dfb2957ea99bf70..925d9b8bb0c09ea4e4f67ebd6ca2f4c8adf2b0f5 100644
--- a/app/models/namespaces/traversal/recursive_scopes.rb
+++ b/app/models/namespaces/traversal/recursive_scopes.rb
@@ -10,6 +10,13 @@ def as_ids
           select('id')
         end
 
+        def roots
+          Gitlab::ObjectHierarchy
+            .new(all)
+            .base_and_ancestors
+            .where(namespaces: { parent_id: nil })
+        end
+
         def self_and_ancestors(include_self: true, hierarchy_order: nil)
           records = Gitlab::ObjectHierarchy.new(all).base_and_ancestors(hierarchy_order: hierarchy_order)
 
diff --git a/config/feature_flags/development/use_traversal_ids_roots.yml b/config/feature_flags/development/use_traversal_ids_roots.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3c0685dc8729490617e5fcb54a24c8bc3c461c43
--- /dev/null
+++ b/config/feature_flags/development/use_traversal_ids_roots.yml
@@ -0,0 +1,8 @@
+---
+name: use_traversal_ids_roots
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74148
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345438
+milestone: '14.5'
+type: development
+group: group::workspace
+default_enabled: false
diff --git a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
index f797eea6b6e23958a1f02f298e8c8e0d47cff620..4c09c1c2a3b1390bd6eb900ad19d0e8bbb8fa3ca 100644
--- a/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
+++ b/spec/support/shared_examples/namespaces/traversal_scope_examples.rb
@@ -49,6 +49,53 @@
     it { is_expected.to eq described_class.column_names }
   end
 
+  shared_examples '.roots' do
+    context 'with only sub-groups' do
+      subject { described_class.where(id: [deep_nested_group_1, nested_group_1, deep_nested_group_2]).roots }
+
+      it { is_expected.to contain_exactly(group_1, group_2) }
+    end
+
+    context 'with only root groups' do
+      subject { described_class.where(id: [group_1, group_2]).roots }
+
+      it { is_expected.to contain_exactly(group_1, group_2) }
+    end
+
+    context 'with all groups' do
+      subject { described_class.where(id: groups).roots }
+
+      it { is_expected.to contain_exactly(group_1, group_2) }
+    end
+  end
+
+  describe '.roots' do
+    context "use_traversal_ids_roots feature flag is true" do
+      before do
+        stub_feature_flags(use_traversal_ids: true)
+        stub_feature_flags(use_traversal_ids_roots: true)
+      end
+
+      it_behaves_like '.roots'
+
+      it 'not make recursive queries' do
+        expect { described_class.where(id: [nested_group_1]).roots.load }.not_to make_queries_matching(/WITH RECURSIVE/)
+      end
+    end
+
+    context "use_traversal_ids_roots feature flag is false" do
+      before do
+        stub_feature_flags(use_traversal_ids_roots: false)
+      end
+
+      it_behaves_like '.roots'
+
+      it 'make recursive queries' do
+        expect { described_class.where(id: [nested_group_1]).roots.load }.to make_queries_matching(/WITH RECURSIVE/)
+      end
+    end
+  end
+
   shared_examples '.self_and_ancestors' do
     subject { described_class.where(id: [nested_group_1, nested_group_2]).self_and_ancestors }