diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fbbe8b8c87246e4f18f821c41cbae62e04f54f24_LmdpdGxhYi1jaS55bWw=..c3ca895d23e471b243537cc9f9a9274342f3bda1_LmdpdGxhYi1jaS55bWw= 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -61,6 +61,8 @@
   QA_BRANCH: 'master'
   ISSUE_BOT_LABELS_EXTRA: "group::distribution"
   BUNDLER_VERSION: "2.3.22"
+  # NOTE: When `NEXT_RUBY_VERSION` is updated, flip
+  # `USE_NEXT_RUBY_VERSION_IN_*` variables to false to avoid surprises.
   NEXT_RUBY_VERSION: "3.0.5"
   GET_GEO_TAG: "0.4.0"
   CANONICAL_PROJECT_PATH: 'gitlab-org/omnibus-gitlab'
diff --git a/config/software/ruby.rb b/config/software/ruby.rb
index fbbe8b8c87246e4f18f821c41cbae62e04f54f24_Y29uZmlnL3NvZnR3YXJlL3J1YnkucmI=..c3ca895d23e471b243537cc9f9a9274342f3bda1_Y29uZmlnL3NvZnR3YXJlL3J1YnkucmI= 100644
--- a/config/software/ruby.rb
+++ b/config/software/ruby.rb
@@ -22,5 +22,5 @@
 
 skip_transitive_dependency_licensing true
 
-# Follow the Ruby upgrade guidewhen changing the ruby version
+# Follow the Ruby upgrade guide when changing the ruby version
 # link: https://docs.gitlab.com/ee/development/ruby_upgrade.html
@@ -26,10 +26,29 @@
 # link: https://docs.gitlab.com/ee/development/ruby_upgrade.html
-# Bundle Ruby 2 if either (or multiple) of the following conditions are met:
-# 1. `RUBY2_BUILD` variable is set to true
-# 2. Running on stable branch
-# 3. Running on regular (non-auto-deploy) tag
-# 4. Running on auto-deploy tag, but variable `USE_NEXT_RUBY_VERSION_IN_AUTODEPLOY` is not set to true
-# In all other scenarios, bundle Ruby 3
-if Gitlab::Util.get_env('RUBY2_BUILD') == 'true' || Build::Check.on_stable_branch? || Build::Check.on_regular_tag? || (Build::Check.is_auto_deploy_tag? && Gitlab::Util.get_env('USE_NEXT_RUBY_VERSION_IN_AUTODEPLOY') != "true")
-  default_version '2.7.7'
+current_ruby_version = '3.0.5'
+
+# NOTE: When this value is updated, flip `USE_NEXT_RUBY_VERSION_IN_*` variable
+# to false to avoid surprises.
+next_ruby_version = Gitlab::Util.get_env('NEXT_RUBY_VERSION') || '3.0.5'
+
+# MRs targeting stable branches should use current Ruby version and ignore next
+# Ruby version. Also, we provide `USE_OLD_RUBY_VERSION` variable to force usage
+# of current Ruby version.
+if Gitlab::Util.get_env('RUBY2_BUILD') == "true" || Gitlab::Util.get_env('USE_OLD_RUBY_VERSION') == "true" || Gitlab::Util.get_env('CI_MERGE_REQUEST_TARGET_BRANCH_NAME')&.match?(/^\d+-\d+-stable$/)
+  default_version current_ruby_version
+# Regular branch builds are switched to newer Ruby version first. So once the
+# `NEXT_RUBY_VERSION` variable is updated, regular branches (master and feature
+# branches) start bundling that version of Ruby. Because nightlies are also
+# technically regular branch builds and because they get auto-deployed to
+# dev.gitlab.org, we provide a variable `USE_NEXT_RUBY_VERSION_IN_NIGHTLY` to
+# control it.
+elsif (Build::Check.on_regular_branch? && !Build::Check.is_nightly?) || (Build::Check.is_nightly? && Gitlab::Util.get_env('USE_NEXT_RUBY_VERSION_IN_NIGHTLY') == "true")
+  default_version next_ruby_version
+# Once feature branches and nightlies have switched to newer Ruby version and
+# we are ready to switch auto-deploy releases to GitLab.com to the new
+# version, flipe the `USE_NEXT_RUBY_VERSION_IN_AUTODEPLOY` to `true`
+elsif Build::Check.is_auto_deploy_tag? && Gitlab::Util.get_env('USE_NEXT_RUBY_VERSION_IN_AUTODEPLOY') == "true"
+  default_version next_ruby_version
+# Once we see new Ruby version running fine in GitLab.com, set new Ruby version
+# as `current_ruby_version` so that they get used in stable branches and tag
+# builds. This change marks "Switch Ruby to new version" as complete.
 else
@@ -35,5 +54,5 @@
 else
-  default_version Gitlab::Util.get_env('NEXT_RUBY_VERSION') || '3.0.5'
+  default_version current_ruby_version
 end
 
 fips_enabled = Build::Check.use_system_ssl?
diff --git a/lib/gitlab/build/check.rb b/lib/gitlab/build/check.rb
index fbbe8b8c87246e4f18f821c41cbae62e04f54f24_bGliL2dpdGxhYi9idWlsZC9jaGVjay5yYg==..c3ca895d23e471b243537cc9f9a9274342f3bda1_bGliL2dpdGxhYi9idWlsZC9jaGVjay5yYg== 100644
--- a/lib/gitlab/build/check.rb
+++ b/lib/gitlab/build/check.rb
@@ -83,6 +83,10 @@
       def on_stable_branch?
         Build::Info.branch_name&.match?(/^\d+-\d+-stable$/)
       end
+
+      def on_regular_branch?
+        Build::Info.branch_name && !on_stable_branch?
+      end
     end
   end
 end
diff --git a/spec/lib/gitlab/build/check_spec.rb b/spec/lib/gitlab/build/check_spec.rb
index fbbe8b8c87246e4f18f821c41cbae62e04f54f24_c3BlYy9saWIvZ2l0bGFiL2J1aWxkL2NoZWNrX3NwZWMucmI=..c3ca895d23e471b243537cc9f9a9274342f3bda1_c3BlYy9saWIvZ2l0bGFiL2J1aWxkL2NoZWNrX3NwZWMucmI= 100644
--- a/spec/lib/gitlab/build/check_spec.rb
+++ b/spec/lib/gitlab/build/check_spec.rb
@@ -261,4 +261,65 @@
       end
     end
   end
+
+  describe 'on_regular_branch?' do
+    context 'when on a regular branch' do
+      before do
+        stub_env_var('CI_COMMIT_BRANCH', 'my-feature-branch')
+        allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(false)
+      end
+
+      it 'returns false' do
+        expect(described_class.on_regular_branch?).to be_truthy
+      end
+    end
+
+    context 'when on a stable branch' do
+      before do
+        stub_env_var('CI_COMMIT_BRANCH', '15-6-stable')
+        allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(false)
+      end
+
+      it 'returns false' do
+        expect(described_class.on_regular_branch?).to be_falsey
+      end
+    end
+
+    context 'when on RC tag' do
+      before do
+        stub_env_var('CI_COMMIT_BRANCH', '')
+        stub_env_var('CI_COMMIT_TAG', '15.8.0+rc42.ce.0')
+        allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(true)
+      end
+
+      it 'returns true' do
+        expect(described_class.on_regular_branch?).to be_falsey
+      end
+    end
+
+    context 'when on stable tag' do
+      before do
+        stub_env_var('CI_COMMIT_BRANCH', '')
+        stub_env_var('CI_COMMIT_TAG', '15.8.0+ce.0')
+        allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(true)
+      end
+
+      it 'returns true' do
+        expect(described_class.on_regular_branch?).to be_falsey
+      end
+    end
+
+    context 'when on auto-deploy tag' do
+      before do
+        stub_env_var('CI_COMMIT_BRANCH', '')
+        stub_env_var('CI_COMMIT_TAG', '15.8.202301050320+b251a9da107.0e5d6807f3a')
+        allow(Build::Info).to receive(:current_git_tag).and_return('15.8.202301050320+b251a9da107.0e5d6807f3a')
+        allow(described_class).to receive(:system).with(/git describe --exact-match/).and_return(true)
+      end
+
+      it 'returns false' do
+        expect(described_class.on_regular_branch?).to be_falsey
+      end
+    end
+  end
 end