diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 4b1cf2fa21746f9e906a16486284ee05b030514b..adf42acdd2b5ff79fe96f874f8b4aeef11c5e2aa 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -43,6 +43,7 @@ class Namespace < ApplicationRecord
   has_many :projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
   has_many :project_statistics
   has_one :namespace_settings, inverse_of: :namespace, class_name: 'NamespaceSetting', autosave: true
+  has_one :namespace_route, foreign_key: :namespace_id, autosave: true, inverse_of: :namespace, class_name: 'Route'
 
   has_many :runner_namespaces, inverse_of: :namespace, class_name: 'Ci::RunnerNamespace'
   has_many :runners, through: :runner_namespaces, source: :runner, class_name: 'Ci::Runner'
diff --git a/app/models/route.rb b/app/models/route.rb
index fcc8459d6e5eaceb9e1f519a9c0aeaf17391027b..12b2d5c5bb2d92bba988b8c5241bb2c9528d582e 100644
--- a/app/models/route.rb
+++ b/app/models/route.rb
@@ -5,6 +5,7 @@ class Route < ApplicationRecord
   include Gitlab::SQL::Pattern
 
   belongs_to :source, polymorphic: true, inverse_of: :route # rubocop:disable Cop/PolymorphicAssociations
+  belongs_to :namespace, inverse_of: :namespace_route
   validates :source, presence: true
 
   validates :path,
diff --git a/db/migrate/20220105121325_add_route_namespace_reference.rb b/db/migrate/20220105121325_add_route_namespace_reference.rb
new file mode 100644
index 0000000000000000000000000000000000000000..77bd0530b8a83b16930dd215d5408983e2babb93
--- /dev/null
+++ b/db/migrate/20220105121325_add_route_namespace_reference.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddRouteNamespaceReference < Gitlab::Database::Migration[1.0]
+  enable_lock_retries!
+
+  def up
+    add_column :routes, :namespace_id, :bigint unless column_exists?(:routes, :namespace_id)
+  end
+
+  def down
+    remove_column :routes, :namespace_id if column_exists?(:routes, :namespace_id)
+  end
+end
diff --git a/db/migrate/20220107091629_add_route_namespace_index.rb b/db/migrate/20220107091629_add_route_namespace_index.rb
new file mode 100644
index 0000000000000000000000000000000000000000..bc1044a24da30b7f6a9830c8c89e6bed826c14a3
--- /dev/null
+++ b/db/migrate/20220107091629_add_route_namespace_index.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddRouteNamespaceIndex < Gitlab::Database::Migration[1.0]
+  disable_ddl_transaction!
+  INDEX_NAME = 'index_routes_on_namespace_id'
+
+  def up
+    add_concurrent_index :routes, :namespace_id, unique: true, name: INDEX_NAME
+    add_concurrent_foreign_key :routes, :namespaces, column: :namespace_id, on_delete: :nullify, reverse_lock_order: true
+  end
+
+  def down
+    with_lock_retries do
+      remove_foreign_key_if_exists :routes, column: :namespace_id
+    end
+
+    remove_concurrent_index_by_name :routes, INDEX_NAME
+  end
+end
diff --git a/db/schema_migrations/20220105121325 b/db/schema_migrations/20220105121325
new file mode 100644
index 0000000000000000000000000000000000000000..384616aba7f6f54acdb9436545fa2a152255cc26
--- /dev/null
+++ b/db/schema_migrations/20220105121325
@@ -0,0 +1 @@
+27ca3977a7569e98271eeb2bd224be1cfe5452ab3778665325b89bf966e07942
\ No newline at end of file
diff --git a/db/schema_migrations/20220107091629 b/db/schema_migrations/20220107091629
new file mode 100644
index 0000000000000000000000000000000000000000..a14f97d77ebad04310f052f6581178b782f4963c
--- /dev/null
+++ b/db/schema_migrations/20220107091629
@@ -0,0 +1 @@
+ef1a7c5f7b10640a0ddc669528dcdb02fd2525d716562f928578e8902a07a832
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index af32c03c83ab1d10d8dc41413a9022a6fe3de701..d8ad20e20cb8263368e7bb5fe3bfe4e17308787e 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -19236,7 +19236,8 @@ CREATE TABLE routes (
     path character varying NOT NULL,
     created_at timestamp without time zone,
     updated_at timestamp without time zone,
-    name character varying
+    name character varying,
+    namespace_id bigint
 );
 
 CREATE SEQUENCE routes_id_seq
@@ -27396,6 +27397,8 @@ CREATE INDEX index_reviews_on_project_id ON reviews USING btree (project_id);
 
 CREATE INDEX index_route_on_name_trigram ON routes USING gin (name gin_trgm_ops);
 
+CREATE UNIQUE INDEX index_routes_on_namespace_id ON routes USING btree (namespace_id);
+
 CREATE UNIQUE INDEX index_routes_on_path ON routes USING btree (path);
 
 CREATE INDEX index_routes_on_path_text_pattern_ops ON routes USING btree (path varchar_pattern_ops);
@@ -29305,6 +29308,9 @@ ALTER TABLE ONLY merge_requests
 ALTER TABLE ONLY ci_builds
     ADD CONSTRAINT fk_6661f4f0e8 FOREIGN KEY (resource_group_id) REFERENCES ci_resource_groups(id) ON DELETE SET NULL;
 
+ALTER TABLE ONLY routes
+    ADD CONSTRAINT fk_679ff8213d FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE SET NULL;
+
 ALTER TABLE ONLY application_settings
     ADD CONSTRAINT fk_693b8795e4 FOREIGN KEY (push_rule_id) REFERENCES push_rules(id) ON DELETE SET NULL;
 
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 1981e8c0291856f02b2b7cc8d9f1c9bc78bec790..03e46f0d7b993c9d0ecf9595204433d5e9f2027d 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -28,6 +28,7 @@
     it { is_expected.to have_one :onboarding_progress }
     it { is_expected.to have_one :admin_note }
     it { is_expected.to have_many :pending_builds }
+    it { is_expected.to have_one :namespace_route }
 
     describe '#children' do
       let_it_be(:group) { create(:group) }
diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb
index b2fa9c2453501145b38a5816a15772787f16916a..0489a4fb995f9bfa7b73027398c79acb6d507472 100644
--- a/spec/models/route_spec.rb
+++ b/spec/models/route_spec.rb
@@ -8,6 +8,7 @@
 
   describe 'relationships' do
     it { is_expected.to belong_to(:source) }
+    it { is_expected.to belong_to(:namespace) }
   end
 
   describe 'validations' do