diff --git a/.gitignore b/.gitignore
index 914daba7994efcdd658a65a4a6240cc2b64fb14d..4eb7ce8303d70f8252f308e70d41c6895ca47893 100644
--- a/.gitignore
+++ b/.gitignore
@@ -113,4 +113,4 @@ tags.temp
 # Vite uses dotenv and suggests to ignore local-only env files. See
 # https://vitejs.dev/guide/env-and-mode.html#env-files
 *.local
-
+/config/vite.gdk.json
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 6739fc57a1f01238ac308a1e9b5b818fb43b59a9..f4d9d616851cfeed6a95b2e5cb81a8ad8ae94099 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -116,7 +116,7 @@ def self.endpoint_id_for_action(action_name)
   content_security_policy do |p|
     next if p.directives.blank?
 
-    if Rails.env.development? && Feature.enabled?(:vite)
+    if helpers.vite_enabled?
       vite_host = ViteRuby.instance.config.host
       vite_port = ViteRuby.instance.config.port
       vite_origin = "#{vite_host}:#{vite_port}"
diff --git a/app/helpers/vite_helper.rb b/app/helpers/vite_helper.rb
index 5096d3649b7bf9a0df3ea5dadda28a885f76b4a9..a8ecfe51f28fa0e3a0c06a785a4cb60612f14362 100644
--- a/app/helpers/vite_helper.rb
+++ b/app/helpers/vite_helper.rb
@@ -1,13 +1,14 @@
 # frozen_string_literal: true
 
 module ViteHelper
-  private
+  def vite_enabled?
+    # vite is not production ready yet
+    return false if Rails.env.production?
+    # Enable vite if explicitly turned on in the GDK
+    return ViteRuby.env['VITE_ENABLED'] if ViteRuby.env.key?('VITE_ENABLED')
 
-  def vite_enabled
-    Feature.enabled?(:vite) && !Rails.env.test? && vite_running
-  end
-
-  def vite_running
-    ViteRuby.instance.dev_server_running?
+    # Enable vite the legacy way (in case GDK hasn't been updated)
+    # This is going to be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/431041
+    Rails.env.development? ? Feature.enabled?(:vite) : false
   end
 end
diff --git a/app/helpers/webpack_helper.rb b/app/helpers/webpack_helper.rb
index 928741687980a216287940fdddd3f2f960f40bc8..e1e2d4581ac470e5831ab978ced00fbb0895efc4 100644
--- a/app/helpers/webpack_helper.rb
+++ b/app/helpers/webpack_helper.rb
@@ -16,7 +16,7 @@ def prefetch_link_tag(source)
   end
 
   def webpack_bundle_tag(bundle)
-    if vite_running
+    if vite_enabled?
       vite_javascript_tag bundle
     else
       javascript_include_tag(*webpack_entrypoint_paths(bundle))
@@ -24,6 +24,8 @@ def webpack_bundle_tag(bundle)
   end
 
   def webpack_preload_asset_tag(asset, options = {})
+    return if vite_enabled?
+
     path = Gitlab::Webpack::Manifest.asset_paths(asset).first
 
     if options.delete(:prefetch)
@@ -38,7 +40,7 @@ def webpack_preload_asset_tag(asset, options = {})
   end
 
   def webpack_controller_bundle_tags
-    return if Feature.enabled?(:vite) && !Rails.env.test?
+    return if vite_enabled?
 
     chunks = []
 
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index 41f663c7c065084a24c8c951ea59c57663c4a945..2c97df90110dace81d0b2200a611231c4e884b1b 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -50,7 +50,7 @@
     = webpack_bundle_tag 'legacy_sentry'
   = webpack_bundle_tag 'performance_bar' if performance_bar_enabled?
 
-  - if vite_enabled
+  - if vite_enabled?
     %meta{ name: 'controller-path', content: controller_full_path }
     - if Rails.env.development?
       = vite_client_tag
diff --git a/config/vite.json b/config/vite.json
index b428b0daec022d5492073eb26665c0d0eb22f8e3..14b5da38ab26121453a23e85df6f7297de0fb8c3 100644
--- a/config/vite.json
+++ b/config/vite.json
@@ -2,17 +2,8 @@
   "all": {
     "sourceCodeDir": "app/assets",
     "entrypointsDir": "javascripts/entrypoints",
-    "devServerConnectTimeout": 3
-  },
-  "development": {
-    "autoBuild": true,
+    "port": 3038,
     "publicOutputDir": "vite-dev",
-    "host": "localhost",
-    "port": 3038
-  },
-  "test": {
-    "autoBuild": true,
-    "publicOutputDir": "vite-test",
-    "port": 3037
+    "devServerConnectTimeout": 3
   }
 }
diff --git a/config/vite.rb b/config/vite.rb
new file mode 100644
index 0000000000000000000000000000000000000000..23495825b6f972a6fe5482e85fb48a5bac14d7e7
--- /dev/null
+++ b/config/vite.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+require 'yaml'
+require_relative '../lib/vite_gdk'
+
+ViteGdk.load_gdk_vite_config
diff --git a/lib/vite_gdk.rb b/lib/vite_gdk.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e4dd85c9c7f3ae02c0be10198866ec10800cf40d
--- /dev/null
+++ b/lib/vite_gdk.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module ViteGdk
+  def self.load_gdk_vite_config
+    # can't use Rails.env.production? here because this file is required outside of Gitlab app instance
+    return if ENV['RAILS_ENV'] == 'production'
+
+    return unless File.exist?(vite_gdk_config_path)
+
+    config = YAML.safe_load_file(vite_gdk_config_path)
+    enabled = config.fetch('enabled', false)
+    ViteRuby.env['VITE_ENABLED'] = enabled
+
+    return unless enabled
+
+    ViteRuby.configure(
+      port: Integer(config.fetch('port', 3038))
+    )
+  end
+
+  def self.vite_gdk_config_path
+    File.join(__dir__, '../config/vite.gdk.json')
+  end
+end
diff --git a/spec/helpers/webpack_helper_spec.rb b/spec/helpers/webpack_helper_spec.rb
index 23585c4723998a6f4403ebaf42a2aa1276d32de7..8cbc4db9108bf8260fd9a0c08d1c37a9a87925ce 100644
--- a/spec/helpers/webpack_helper_spec.rb
+++ b/spec/helpers/webpack_helper_spec.rb
@@ -43,7 +43,7 @@
       stub_feature_flags(vite: true)
 
       allow(helper).to receive(:vite_javascript_tag).and_return('vite')
-      allow(helper).to receive(:vite_running).and_return(true)
+      allow(helper).to receive(:vite_enabled?).and_return(true)
     end
 
     describe '#webpack_bundle_tag' do
diff --git a/spec/lib/vite_gdk_spec.rb b/spec/lib/vite_gdk_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..fed2ca6921faebb00c2e529c938b37ff73a7b572
--- /dev/null
+++ b/spec/lib/vite_gdk_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+VITE_GDK_CONFIG_FILEPATH = "config/vite.gdk.json"
+
+RSpec.describe ViteGdk, feature_category: :tooling do
+  before do
+    allow(ViteRuby).to receive(:configure)
+    allow(ViteRuby.env).to receive(:[]=)
+    allow(YAML).to receive(:safe_load_file)
+  end
+
+  describe '#load_gdk_vite_config' do
+    context 'when not in production environment' do
+      before do
+        stub_env('RAILS_ENV', nil)
+      end
+
+      context 'when it loads file successfully' do
+        it 'configures ViteRuby' do
+          expect(File).to receive(:exist?) do |file_path|
+            expect(file_path).to end_with(VITE_GDK_CONFIG_FILEPATH)
+          end.and_return(true)
+          expect(YAML).to receive(:safe_load_file) do |file_path|
+            expect(file_path).to end_with(VITE_GDK_CONFIG_FILEPATH)
+          end.and_return('enabled' => true, 'port' => 3038)
+          expect(ViteRuby).to receive(:configure).with(port: 3038)
+          expect(ViteRuby.env).to receive(:[]=).with('VITE_ENABLED', true)
+
+          described_class.load_gdk_vite_config
+        end
+      end
+
+      context 'when config file is missing' do
+        it 'does nothing' do
+          expect(File).to receive(:exist?) do |file_path|
+            expect(file_path).to end_with(VITE_GDK_CONFIG_FILEPATH)
+          end.and_return(false)
+          expect(ViteRuby).not_to receive(:configure)
+          expect(ViteRuby.env).not_to receive(:[]=).with('VITE_ENABLED', false)
+          expect(ViteRuby.env).not_to receive(:[]=).with('VITE_ENABLED', true)
+
+          described_class.load_gdk_vite_config
+        end
+      end
+    end
+
+    context 'when in production environment' do
+      before do
+        stub_env('RAILS_ENV', 'production')
+      end
+
+      it 'does not load and configure ViteRuby' do
+        expect(YAML).not_to receive(:safe_load_file)
+        expect(ViteRuby).not_to receive(:configure)
+        expect(ViteRuby.env).not_to receive(:[]=).with('VITE_ENABLED')
+
+        described_class.load_gdk_vite_config
+      end
+    end
+  end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 2dd4e92eee9b3c94091f0e86c7466e3ceff157ee..4876acfce8a3b294683c90576bd7e83b79348822 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -327,6 +327,7 @@
       # Postgres is the primary data source, and ClickHouse only when enabled in certain cases.
       stub_feature_flags(clickhouse_data_collection: false)
 
+      # This is going to be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/431041
       stub_feature_flags(vite: false)
     else
       unstub_all_feature_flags