diff --git a/app/assets/javascripts/search/sidebar/components/app.vue b/app/assets/javascripts/search/sidebar/components/app.vue
index 928cd46c9eb24dc27ed9bac90c74b2403e0bd1b0..60de63c7d7ab132807a2f1177c8e95385b1beea6 100644
--- a/app/assets/javascripts/search/sidebar/components/app.vue
+++ b/app/assets/javascripts/search/sidebar/components/app.vue
@@ -21,7 +21,7 @@ export default {
       return this.currentScope === SCOPE_ISSUES || this.currentScope === SCOPE_MERGE_REQUESTS;
     },
     showBlobFilter() {
-      return this.currentScope === SCOPE_BLOB && this.glFeatures.searchBlobsLanguageAggregation;
+      return this.currentScope === SCOPE_BLOB;
     },
   },
 };
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index d1f846ae55cd4aff20a39b07122c44104820c800..549b6286d96368feb293c7089721c8ac32dbf798 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -31,9 +31,6 @@ def self.search_rate_limited_endpoints
   end
   before_action :check_search_rate_limit!, only: search_rate_limited_endpoints
 
-  before_action only: :show do
-    push_frontend_feature_flag(:search_blobs_language_aggregation, current_user)
-  end
   before_action only: :show do
     update_scope_for_code_search
   end
diff --git a/config/feature_flags/development/search_blobs_language_aggregation.yml b/config/feature_flags/development/search_blobs_language_aggregation.yml
deleted file mode 100644
index da1b81dc52c2640c1209109affc151a00adf730c..0000000000000000000000000000000000000000
--- a/config/feature_flags/development/search_blobs_language_aggregation.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: search_blobs_language_aggregation
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/71937
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/342621
-milestone: '14.4'
-type: development
-group: group::global search
-default_enabled: false
diff --git a/doc/user/search/index.md b/doc/user/search/index.md
index 60d428850acf3360e3cdc9a8c303def0f4b6f586..310d733800a204c63d9af91348dbe8432e0e42b5 100644
--- a/doc/user/search/index.md
+++ b/doc/user/search/index.md
@@ -82,7 +82,16 @@ where the results were found.
 1. From the code search result, hover over the line number.
 1. On the left, select **View blame**.
 
-   ![code search results](img/code_search_git_blame_v15_1.png)
+![code search results](img/code_search_git_blame_v15_1.png)
+
+### Filter code search results by language
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/342651) in GitLab 15.10.
+
+To filter code search results by one or more languages:
+
+1. On the code search page, on the left sidebar, select one or more languages.
+1. On the left sidebar, select **Apply**.
 
 ## Search for projects by full path
 
diff --git a/ee/lib/elastic/latest/git_class_proxy.rb b/ee/lib/elastic/latest/git_class_proxy.rb
index b696759f9074de19665e21ee0abf63bec48f9dee..7bffc89b18f5c9dce27d15e2219c2dd981c2ab91 100644
--- a/ee/lib/elastic/latest/git_class_proxy.rb
+++ b/ee/lib/elastic/latest/git_class_proxy.rb
@@ -38,8 +38,6 @@ def elastic_search_as_found_blob(query, page: 1, per: 20, options: {}, preload_m
       end
 
       def blob_aggregations(query, options)
-        return [] unless ::Feature.enabled?(:search_blobs_language_aggregation, options[:current_user])
-
         query_hash, options = blob_query(query, options: options.merge(features: 'repository', aggregation: true))
 
         results = search(query_hash, options)
@@ -87,7 +85,7 @@ def options_filter_context(type, options)
           }
         end
 
-        if languages.any? && type == :blob && (!options[:count_only] || options[:aggregation]) && ::Feature.enabled?(:search_blobs_language_aggregation, options[:current_user])
+        if languages.any? && type == :blob && (!options[:count_only] || options[:aggregation])
           filters << {
             terms: {
               _name: context.name(type, :match, :languages),
@@ -335,8 +333,7 @@ def blob_query(query, type: 'blob', page: 1, per: 20, options: {})
           }
         end
 
-        current_user = options[:current_user]
-        if type == 'blob' && aggregation && ::Feature.enabled?(:search_blobs_language_aggregation, current_user)
+        if type == 'blob' && aggregation
           query_hash[:aggs] = {
             language: {
               terms: {
diff --git a/ee/spec/lib/elastic/latest/git_class_proxy_spec.rb b/ee/spec/lib/elastic/latest/git_class_proxy_spec.rb
index bc3b2ea8c4323d631d8e41c5536fa0e50d2c8269..47c09aa1b7af2c1b9d702c3c69464ed3800f9fd2 100644
--- a/ee/spec/lib/elastic/latest/git_class_proxy_spec.rb
+++ b/ee/spec/lib/elastic/latest/git_class_proxy_spec.rb
@@ -66,18 +66,6 @@
       expect(result.first.buckets.first[:key]).to eq('Markdown')
       expect(result.first.buckets.first[:count]).to eq(2)
     end
-
-    context 'when search_blobs_language_aggregation feature flag is disabled' do
-      before do
-        stub_feature_flags(search_blobs_language_aggregation: false)
-      end
-
-      it 'returns empty array' do
-        result = subject.blob_aggregations('This guide details how contribute to GitLab', options)
-
-        expect(result).to match_array([])
-      end
-    end
   end
 
   it "names elasticsearch queries" do
diff --git a/ee/spec/lib/gitlab/elastic/project_search_results_spec.rb b/ee/spec/lib/gitlab/elastic/project_search_results_spec.rb
index 0c3eb2b54c09fe24ce8aa640ce7afe10385c021b..5e1d12a7f0e620d9080106c941b2b3964855d1f7 100644
--- a/ee/spec/lib/gitlab/elastic/project_search_results_spec.rb
+++ b/ee/spec/lib/gitlab/elastic/project_search_results_spec.rb
@@ -194,24 +194,28 @@
       'commits'        | nil        | false
       'users'          | nil        | false
       'unknown'        | nil        | false
-      'blobs'          | 'language' | :search_blobs_language_aggregation
+      'blobs'          | 'language' | false
     end
 
     with_them do
       context 'when feature flag is enabled for user' do
+        let(:feature_enabled) { true }
+
         before do
           stub_feature_flags(feature_flag => user) if feature_flag
         end
 
-        it_behaves_like 'loads aggregations'
+        it_behaves_like 'loads expected aggregations'
       end
 
       context 'when feature flag is disabled for user' do
+        let(:feature_enabled) { false }
+
         before do
           stub_feature_flags(feature_flag => false) if feature_flag
         end
 
-        it_behaves_like 'does not load aggregations'
+        it_behaves_like 'loads expected aggregations'
       end
     end
 
diff --git a/ee/spec/lib/gitlab/elastic/search_results_spec.rb b/ee/spec/lib/gitlab/elastic/search_results_spec.rb
index d6b82038788f7de021ae09141e0c344930d5ec8b..a21e74a5aa86065a2dfce3aaf74198cf9d887a1b 100644
--- a/ee/spec/lib/gitlab/elastic/search_results_spec.rb
+++ b/ee/spec/lib/gitlab/elastic/search_results_spec.rb
@@ -84,26 +84,30 @@
       'users'          | nil        | false
       'epics'          | nil        | false
       'unknown'        | nil        | false
-      'blobs'          | 'language' | :search_blobs_language_aggregation
+      'blobs'          | 'language' | false
     end
 
     with_them do
       context 'when feature flag is enabled for user' do
+        let(:feature_enabled) { true }
+
         before do
           stub_feature_flags(feature_flag => user) if feature_flag
           results.objects(scope) # run search to populate aggregations
         end
 
-        it_behaves_like 'loads aggregations'
+        it_behaves_like 'loads expected aggregations'
       end
 
       context 'when feature flag is disabled for user' do
+        let(:feature_enabled) { false }
+
         before do
           stub_feature_flags(feature_flag => false) if feature_flag
           results.objects(scope) # run search to populate aggregations
         end
 
-        it_behaves_like 'does not load aggregations'
+        it_behaves_like 'loads expected aggregations'
       end
     end
   end
diff --git a/ee/spec/support/shared_examples/lib/gitlab/elastic/search_results_shared_examples.rb b/ee/spec/support/shared_examples/lib/gitlab/elastic/search_results_shared_examples.rb
index 8a4f59058ed2504c8b612fbd4be466b9df5065ff..bbbe7961688bf0fe701f68874b28746cc3991133 100644
--- a/ee/spec/support/shared_examples/lib/gitlab/elastic/search_results_shared_examples.rb
+++ b/ee/spec/support/shared_examples/lib/gitlab/elastic/search_results_shared_examples.rb
@@ -2,7 +2,7 @@
 
 RSpec.shared_examples 'does not hit Elasticsearch twice for objects and counts' do |scopes|
   scopes.each do |scope|
-    context "for scope #{scope}", :elastic, :request_store do
+    context "for scope #{scope}", :elastic, :request_store, feature_category: :global_search do
       it 'makes 1 Elasticsearch query' do
         # We want to warm the cache for checking migrations have run since we
         # don't want to count these requests as searches
@@ -28,7 +28,7 @@
       allow(::Gitlab::PerformanceBar).to receive(:enabled_for_request?).and_return(true)
     end
 
-    context "for scope #{scope}", :elastic, :request_store do
+    context "for scope #{scope}", :elastic, :request_store, feature_category: :global_search do
       it 'makes count query' do
         # We want to warm the cache for checking migrations have run since we
         # don't want to count these requests as searches
@@ -49,24 +49,18 @@
   end
 end
 
-RSpec.shared_examples 'loads aggregations' do
+RSpec.shared_examples 'loads expected aggregations' do
   let(:query) { 'hello world' }
 
-  it 'returns the expected aggregations' do
+  it 'returns the expected aggregations', feature_category: :global_search do
     expect(aggregations).to be_kind_of(Array)
 
-    if expected_aggregation_name
+    if expected_aggregation_name && (!feature_flag || feature_enabled)
       expect(aggregations.size).to eq(1)
       expect(aggregations.first.name).to eq(expected_aggregation_name)
     else
+      expect(aggregations).to be_kind_of(Array)
       expect(aggregations).to be_empty
     end
   end
 end
-
-RSpec.shared_examples 'does not load aggregations' do
-  it 'returns an empty array' do
-    expect(aggregations).to be_kind_of(Array)
-    expect(aggregations).to be_empty
-  end
-end
diff --git a/spec/frontend/search/sidebar/components/app_spec.js b/spec/frontend/search/sidebar/components/app_spec.js
index bbe04ba67f19a04117ec75d0429c76d8f0ad7553..8a35ae96d5ec5ad709a1d90dbc66505c1fd5e04d 100644
--- a/spec/frontend/search/sidebar/components/app_spec.js
+++ b/spec/frontend/search/sidebar/components/app_spec.js
@@ -57,23 +57,23 @@ describe('GlobalSearchSidebar', () => {
     });
 
     describe.each`
-      scope               | showFilters | ShowsLanguage
+      scope               | showFilters | showsLanguage
       ${'issues'}         | ${true}     | ${false}
       ${'merge_requests'} | ${true}     | ${false}
       ${'projects'}       | ${false}    | ${false}
       ${'blobs'}          | ${false}    | ${true}
-    `('sidebar scope: $scope', ({ scope, showFilters, ShowsLanguage }) => {
+    `('sidebar scope: $scope', ({ scope, showFilters, showsLanguage }) => {
       beforeEach(() => {
         getterSpies.currentScope = jest.fn(() => scope);
-        createComponent({ urlQuery: { scope } }, { searchBlobsLanguageAggregation: true });
+        createComponent({ urlQuery: { scope } });
       });
 
       it(`${!showFilters ? "doesn't" : ''} shows filters`, () => {
         expect(findFilters().exists()).toBe(showFilters);
       });
 
-      it(`${!ShowsLanguage ? "doesn't" : ''} shows language filters`, () => {
-        expect(findLanguageAggregation().exists()).toBe(ShowsLanguage);
+      it(`${!showsLanguage ? "doesn't" : ''} shows language filters`, () => {
+        expect(findLanguageAggregation().exists()).toBe(showsLanguage);
       });
     });
 
@@ -86,22 +86,4 @@ describe('GlobalSearchSidebar', () => {
       });
     });
   });
-
-  describe('when search_blobs_language_aggregation is enabled', () => {
-    beforeEach(() => {
-      createComponent({ urlQuery: { scope: 'blobs' } }, { searchBlobsLanguageAggregation: true });
-    });
-    it('shows the language filter', () => {
-      expect(findLanguageAggregation().exists()).toBe(true);
-    });
-  });
-
-  describe('when search_blobs_language_aggregation is disabled', () => {
-    beforeEach(() => {
-      createComponent({ urlQuery: { scope: 'blobs' } }, { searchBlobsLanguageAggregation: false });
-    });
-    it('hides the language filter', () => {
-      expect(findLanguageAggregation().exists()).toBe(false);
-    });
-  });
 });
diff --git a/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb
index a3e4379f4d389c2637913d03455dd8929fdd4e60..18545698c2790f5d9fc95b654cabc4b102755261 100644
--- a/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/search_language_filter_shared_examples.rb
@@ -26,29 +26,4 @@
     expect(blob_results.size).to eq(5)
     expect(paths).to match_array(expected_paths)
   end
-
-  context 'when the search_blobs_language_aggregation feature flag is disabled' do
-    before do
-      stub_feature_flags(search_blobs_language_aggregation: false)
-    end
-
-    it 'does not filter by language', :sidekiq_inline, :aggregate_failures do
-      expected_paths = %w[
-        CHANGELOG
-        CONTRIBUTING.md
-        bar/branch-test.txt
-        custom-highlighting/test.gitlab-custom
-        files/ruby/popen.rb
-        files/ruby/regex.rb
-        files/ruby/version_info.rb
-        files/whitespace
-        encoding/test.txt
-        files/markdown/ruby-style-guide.md
-      ]
-
-      paths = blob_results.map { |blob| blob.binary_path }
-      expect(blob_results.size).to eq(10)
-      expect(paths).to match_array(expected_paths)
-    end
-  end
 end