diff --git a/.eslintrc.yml b/.eslintrc.yml
index 1c6b5a939d220bb47932a44fdbe111ce2f04c34a..c20ad9b5b34bbe371578a3c7e934d8a854545e5f 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -230,3 +230,11 @@ overrides:
       - '{,ee/}spec/contracts/consumer/**/*'
     rules:
       '@gitlab/require-i18n-strings': off
+  - files:
+      - 'app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql'
+      - 'app/assets/javascripts/projects/settings/repository/branch_rules/graphql/mutations/create_branch_rule.mutation.graphql'
+      - 'app/assets/javascripts/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql'
+      - 'ee/app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql'
+      - 'ee/app/assets/javascripts/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql'
+    rules:
+      '@graphql-eslint/require-id-when-available': off
diff --git a/app/graphql/types/projects/branch_rule_type.rb b/app/graphql/types/projects/branch_rule_type.rb
index f8ea3644945209060fc4b578f59c56cc9232c8d0..d960361c4e63ea22964f29fda388fa955c13cede 100644
--- a/app/graphql/types/projects/branch_rule_type.rb
+++ b/app/graphql/types/projects/branch_rule_type.rb
@@ -9,6 +9,9 @@ class BranchRuleType < BaseObject
 
       alias_method :branch_rule, :object
 
+      field :id, ::Types::GlobalIDType[::Projects::BranchRule],
+            description: 'ID of the branch rule.'
+
       field :name,
             type: GraphQL::Types::String,
             null: false,
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 32f1ab9c5f41fff8e48e2712c3e6a21e79896564..3cc65140b036d1bad43869d95bb556faee2e3b16 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -15552,6 +15552,7 @@ Branch rules configured for a rule target.
 | <a id="branchrulebranchprotection"></a>`branchProtection` | [`BranchProtection`](#branchprotection) | Branch protections configured for this branch rule. |
 | <a id="branchrulecreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp of when the branch rule was created. |
 | <a id="branchruleexternalstatuschecks"></a>`externalStatusChecks` | [`ExternalStatusCheckConnection`](#externalstatuscheckconnection) | External status checks configured for this branch rule. (see [Connections](#connections)) |
+| <a id="branchruleid"></a>`id` | [`ProjectsBranchRuleID`](#projectsbranchruleid) | ID of the branch rule. |
 | <a id="branchruleisdefault"></a>`isDefault` | [`Boolean!`](#boolean) | Check if this branch rule protects the project's default branch. |
 | <a id="branchruleisprotected"></a>`isProtected` | [`Boolean!`](#boolean) | Check if this branch rule protects access for the branch. |
 | <a id="branchrulematchingbranchescount"></a>`matchingBranchesCount` | [`Int!`](#int) | Number of existing branches that match this branch rule. |
@@ -33056,6 +33057,12 @@ A `ProjectImportStateID` is a global ID. It is encoded as a string.
 
 An example `ProjectImportStateID` is: `"gid://gitlab/ProjectImportState/1"`.
 
+### `ProjectsBranchRuleID`
+
+A `ProjectsBranchRuleID` is a global ID. It is encoded as a string.
+
+An example `ProjectsBranchRuleID` is: `"gid://gitlab/Projects::BranchRule/1"`.
+
 ### `ProtectedBranchID`
 
 A `ProtectedBranchID` is a global ID. It is encoded as a string.
diff --git a/ee/spec/requests/api/graphql/project/branch_rules_spec.rb b/ee/spec/requests/api/graphql/project/branch_rules_spec.rb
index 3e16ab22031c19b42284d2db075f2bdfbbd264d4..a4796bafc6c11d916fdeb3d64bee9b10d6b7ed67 100644
--- a/ee/spec/requests/api/graphql/project/branch_rules_spec.rb
+++ b/ee/spec/requests/api/graphql/project/branch_rules_spec.rb
@@ -119,6 +119,7 @@ def expect_n_matching_branches_count_fields(count)
 
       it 'includes all fields', :use_sql_query_cache, :aggregate_failures do
         expect(all_branches_rule_data).to include(
+          'id' => all_branches_rule.to_global_id.to_s,
           'name' => all_branches_rule.name,
           'isDefault' => all_branches_rule.default_branch?,
           'isProtected' => all_branches_rule.protected?,
@@ -143,6 +144,7 @@ def expect_n_matching_branches_count_fields(count)
           'externalUrl' => all_branches_external_status_check.external_url
         }])
         expect(all_protected_branches_rule_data).to include(
+          'id' => all_protected_branches_rule.to_global_id.to_s,
           'name' => all_protected_branches_rule.name,
           'isDefault' => all_protected_branches_rule.default_branch?,
           'isProtected' => all_protected_branches_rule.protected?,
@@ -162,6 +164,7 @@ def expect_n_matching_branches_count_fields(count)
         }])
 
         expect(branch_rule_a_data).to include(
+          'id' => branch_rule_a.to_global_id.to_s,
           'name' => branch_rule_a.name,
           'isDefault' => branch_rule_a.default_branch?,
           'isProtected' => branch_rule_a.protected?,
@@ -177,6 +180,7 @@ def expect_n_matching_branches_count_fields(count)
         )
 
         expect(branch_rule_b_data).to include(
+          'id' => branch_rule_b.to_global_id.to_s,
           'name' => branch_rule_b.name,
           'isDefault' => branch_rule_b.default_branch?,
           'isProtected' => branch_rule_b.protected?,
diff --git a/spec/requests/api/graphql/project/branch_rules_spec.rb b/spec/requests/api/graphql/project/branch_rules_spec.rb
index 63537ba5750ce21f95db9d4f8d9f5fd1a921fd96..9506fe1e1290fb5b855e982480fcf264a42a5a7d 100644
--- a/spec/requests/api/graphql/project/branch_rules_spec.rb
+++ b/spec/requests/api/graphql/project/branch_rules_spec.rb
@@ -124,6 +124,7 @@ def expect_n_matching_branches_count_fields(count)
 
       it 'includes all fields', :use_sql_query_cache, :aggregate_failures do
         expect(branch_rule_a_data).to include(
+          'id' => branch_rule_a.to_global_id.to_s,
           'name' => branch_name_a,
           'isDefault' => be_boolean,
           'isProtected' => true,
@@ -137,6 +138,7 @@ def expect_n_matching_branches_count_fields(count)
           branch_name.starts_with?('diff-')
         end
         expect(branch_rule_b_data).to include(
+          'id' => branch_rule_b.to_global_id.to_s,
           'name' => branch_name_b,
           'isDefault' => be_boolean,
           'isProtected' => true,