diff --git a/app/assets/javascripts/work_items/graphql/provider.js b/app/assets/javascripts/work_items/graphql/provider.js
index 676fffb12d83dae4f24da34c2c3287188a3eab78..3ea7b118d5dae8a80cb31c4206eaaf15d2be562f 100644
--- a/app/assets/javascripts/work_items/graphql/provider.js
+++ b/app/assets/javascripts/work_items/graphql/provider.js
@@ -10,6 +10,11 @@ export function createApolloProvider() {
 
   const defaultClient = createDefaultClient(resolvers, {
     typeDefs,
+    cacheConfig: {
+      possibleTypes: {
+        LocalWorkItemWidget: ['LocalTitleWidget'],
+      },
+    },
   });
 
   defaultClient.cache.writeQuery({
@@ -18,7 +23,7 @@ export function createApolloProvider() {
       id: '1',
     },
     data: {
-      workItem: {
+      localWorkItem: {
         __typename: 'LocalWorkItem',
         id: '1',
         type: 'FEATURE',
diff --git a/app/assets/javascripts/work_items/graphql/resolvers.js b/app/assets/javascripts/work_items/graphql/resolvers.js
index 63d5234d0833fed67c4532b8d2d9916078753858..60ad290f493ac2c56e9a388f8048109fd4bce46d 100644
--- a/app/assets/javascripts/work_items/graphql/resolvers.js
+++ b/app/assets/javascripts/work_items/graphql/resolvers.js
@@ -22,7 +22,11 @@ export const resolvers = {
         },
       };
 
-      cache.writeQuery({ query: workItemQuery, variables: { id }, data: { workItem } });
+      cache.writeQuery({
+        query: workItemQuery,
+        variables: { id },
+        data: { localWorkItem: workItem },
+      });
 
       return {
         __typename: 'LocalCreateWorkItemPayload',
@@ -47,7 +51,11 @@ export const resolvers = {
         },
       };
 
-      cache.writeQuery({ query: workItemQuery, variables: { id: input.id }, data: { workItem } });
+      cache.writeQuery({
+        query: workItemQuery,
+        variables: { id: input.id },
+        data: { localWorkItem: workItem },
+      });
 
       return {
         __typename: 'LocalUpdateWorkItemPayload',
diff --git a/app/assets/javascripts/work_items/graphql/typedefs.graphql b/app/assets/javascripts/work_items/graphql/typedefs.graphql
index 177eea0032264ba295f50b13194798dae3d8967d..9091b08bf104b2088822bd031c9dc4ff4b90ecbe 100644
--- a/app/assets/javascripts/work_items/graphql/typedefs.graphql
+++ b/app/assets/javascripts/work_items/graphql/typedefs.graphql
@@ -51,7 +51,7 @@ type LocalUpdateWorkItemPayload {
 }
 
 extend type Query {
-  workItem(id: ID!): LocalWorkItem!
+  localWorkItem(id: ID!): LocalWorkItem!
 }
 
 extend type Mutation {
diff --git a/app/assets/javascripts/work_items/graphql/work_item.query.graphql b/app/assets/javascripts/work_items/graphql/work_item.query.graphql
index 9f173f7c3028b11463643601e6590ffb57c4770e..c4fc7dad56a9b13671d3f16a605bccb49cbbb960 100644
--- a/app/assets/javascripts/work_items/graphql/work_item.query.graphql
+++ b/app/assets/javascripts/work_items/graphql/work_item.query.graphql
@@ -1,7 +1,7 @@
 #import './widget.fragment.graphql'
 
 query WorkItem($id: ID!) {
-  workItem(id: $id) @client {
+  localWorkItem(id: $id) @client {
     id
     type
     widgets {
diff --git a/app/assets/javascripts/work_items/pages/work_item_root.vue b/app/assets/javascripts/work_items/pages/work_item_root.vue
index 4262e169655377a840e0019d5016253c5ee81349..9e6ace5d48e52f9bd6990a7a930f42fd16ac46a0 100644
--- a/app/assets/javascripts/work_items/pages/work_item_root.vue
+++ b/app/assets/javascripts/work_items/pages/work_item_root.vue
@@ -36,6 +36,9 @@ export default {
           id: this.id,
         };
       },
+      update(data) {
+        return data.localWorkItem;
+      },
     },
   },
   computed: {
diff --git a/app/graphql/resolvers/work_item_resolver.rb b/app/graphql/resolvers/work_item_resolver.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b1733d657e49dee361b0a946d0f27e426ccb5fd8
--- /dev/null
+++ b/app/graphql/resolvers/work_item_resolver.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Resolvers
+  class WorkItemResolver < BaseResolver
+    include Gitlab::Graphql::Authorize::AuthorizeResource
+
+    authorize :read_issue
+
+    type Types::WorkItemType, null: true
+
+    argument :id, ::Types::GlobalIDType[::WorkItem], required: true, description: 'Global ID of the work item.'
+
+    def resolve(id:)
+      work_item = authorized_find!(id: id)
+      return unless Feature.enabled?(:work_items, work_item.project)
+
+      work_item
+    end
+
+    private
+
+    def find_object(id:)
+      # TODO: remove this line when the compatibility layer is removed
+      # See: https://gitlab.com/gitlab-org/gitlab/-/issues/257883
+      id = ::Types::GlobalIDType[::WorkItem].coerce_isolated_input(id)
+      GitlabSchema.find_by_gid(id)
+    end
+  end
+end
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index 4a4d6727c3ffd8fba1214d0ccd51afbb65fad85b..6e89a51618ff0619471808a3c26d54171fc8f007 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -87,6 +87,11 @@ class QueryType < ::Types::BaseObject
             argument :id, ::Types::GlobalIDType[::Issue], required: true, description: 'Global ID of the issue.'
           end
 
+    field :work_item, Types::WorkItemType,
+          null: true,
+          resolver: Resolvers::WorkItemResolver,
+          description: 'Find a work item. Returns `null` if `work_items` feature flag is disabled.'
+
     field :merge_request, Types::MergeRequestType,
           null: true,
           description: 'Find a merge request.' do
diff --git a/app/graphql/types/work_item_type.rb b/app/graphql/types/work_item_type.rb
index 15a5557b4892a12c2833b4a27e2e514188bed934..78cef150b11d9a2a42ef4527a8ae75a707336013 100644
--- a/app/graphql/types/work_item_type.rb
+++ b/app/graphql/types/work_item_type.rb
@@ -12,6 +12,8 @@ class WorkItemType < BaseObject
           description: 'Global ID of the work item.'
     field :iid, GraphQL::Types::ID, null: false,
           description: 'Internal ID of the work item.'
+    field :lock_version, GraphQL::Types::Int, null: false,
+          description: 'Lock version of the work item. Incremented each time the work item is updated.'
     field :state, WorkItemStateEnum, null: false,
           description: 'State of the work item.'
     field :title, GraphQL::Types::String, null: false,
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index f126c828240c9b3d813d574faff7ba9f019d3d81..15c380795b2158144b41555433121254a4b180c2 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -560,6 +560,18 @@ Returns [`Vulnerability`](#vulnerability).
 | ---- | ---- | ----------- |
 | <a id="queryvulnerabilityid"></a>`id` | [`VulnerabilityID!`](#vulnerabilityid) | Global ID of the Vulnerability. |
 
+### `Query.workItem`
+
+Find a work item. Returns `null` if `work_items` feature flag is disabled.
+
+Returns [`WorkItem`](#workitem).
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="queryworkitemid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. |
+
 ## `Mutation` type
 
 The `Mutation` type contains all the mutations you can execute.
@@ -16726,6 +16738,7 @@ Represents vulnerability letter grades with associated projects.
 | <a id="workitemdescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. |
 | <a id="workitemid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. |
 | <a id="workitemiid"></a>`iid` | [`ID!`](#id) | Internal ID of the work item. |
+| <a id="workitemlockversion"></a>`lockVersion` | [`Int!`](#int) | Lock version of the work item. Incremented each time the work item is updated. |
 | <a id="workitemstate"></a>`state` | [`WorkItemState!`](#workitemstate) | State of the work item. |
 | <a id="workitemtitle"></a>`title` | [`String!`](#string) | Title of the work item. |
 | <a id="workitemtitlehtml"></a>`titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title`. |
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index a98722bc4656d753dcfa38b5301d616a82623076..42d04153ef0e77582aa31c8683cf7428e53482d3 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -1,5 +1,5 @@
 export const workItemQueryResponse = {
-  workItem: {
+  localWorkItem: {
     __typename: 'LocalWorkItem',
     id: '1',
     type: 'FEATURE',
diff --git a/spec/graphql/resolvers/work_item_resolver_spec.rb b/spec/graphql/resolvers/work_item_resolver_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c7e2beecb515500247ea6b59a8ebfe6190c140e6
--- /dev/null
+++ b/spec/graphql/resolvers/work_item_resolver_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::WorkItemResolver do
+  include GraphqlHelpers
+
+  describe '#resolve' do
+    let_it_be(:developer) { create(:user) }
+    let_it_be(:project) { create(:project, :private).tap { |project| project.add_developer(developer) } }
+    let_it_be(:work_item) { create(:work_item, project: project) }
+
+    let(:current_user) { developer }
+
+    subject(:resolved_work_item) { resolve_work_item('id' => work_item.to_gid.to_s) }
+
+    context 'when the user can read the work item' do
+      it { is_expected.to eq(work_item) }
+    end
+
+    context 'when the user can not read the work item' do
+      let(:current_user) { create(:user) }
+
+      it 'raises a resource not available error' do
+        expect { resolved_work_item }.to raise_error(::Gitlab::Graphql::Errors::ResourceNotAvailable)
+      end
+    end
+
+    context 'when the work_items feature flag is disabled' do
+      before do
+        stub_feature_flags(work_items: false)
+      end
+
+      it { is_expected.to be_nil }
+    end
+  end
+
+  private
+
+  def resolve_work_item(args = {})
+    resolve(described_class, args: args, ctx: { current_user: current_user })
+  end
+end
diff --git a/spec/graphql/types/work_item_type_spec.rb b/spec/graphql/types/work_item_type_spec.rb
index d0bab477f36cb95053d791b61d995bd817b935c8..4e44123d475dc328cd7baad720154a3a5d584614 100644
--- a/spec/graphql/types/work_item_type_spec.rb
+++ b/spec/graphql/types/work_item_type_spec.rb
@@ -5,8 +5,10 @@
 RSpec.describe GitlabSchema.types['WorkItem'] do
   specify { expect(described_class.graphql_name).to eq('WorkItem') }
 
+  specify { expect(described_class).to require_graphql_authorizations(:read_issue) }
+
   it 'has specific fields' do
-    fields = %i[description description_html id iid state title title_html work_item_type]
+    fields = %i[description description_html id iid lock_version state title title_html work_item_type]
 
     fields.each do |field_name|
       expect(described_class).to have_graphql_fields(*fields)
diff --git a/spec/requests/api/graphql/work_item_spec.rb b/spec/requests/api/graphql/work_item_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5ed9a3bf7e61ec910002062495e9485a4de36293
--- /dev/null
+++ b/spec/requests/api/graphql/work_item_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Query.work_item(id)' do
+  include GraphqlHelpers
+
+  let_it_be(:developer) { create(:user) }
+  let_it_be(:project) { create(:project, :private).tap { |project| project.add_developer(developer) } }
+  let_it_be(:work_item) { create(:work_item, project: project) }
+
+  let(:current_user) { developer }
+  let(:work_item_data) { graphql_data['workItem'] }
+  let(:work_item_fields) { all_graphql_fields_for('WorkItem') }
+
+  let(:query) do
+    graphql_query_for('workItem', { 'id' => work_item.to_gid.to_s }, work_item_fields)
+  end
+
+  context 'when the user can read the work item' do
+    before do
+      post_graphql(query, current_user: current_user)
+    end
+
+    it_behaves_like 'a working graphql query'
+
+    it 'returns all fields' do
+      expect(work_item_data).to include(
+        'description' => work_item.description,
+        'id' => work_item.to_gid.to_s,
+        'iid' => work_item.iid.to_s,
+        'lockVersion' => work_item.lock_version,
+        'state' => "OPEN",
+        'title' => work_item.title,
+        'workItemType' => hash_including('id' => work_item.work_item_type.to_gid.to_s)
+      )
+    end
+  end
+
+  context 'when the user can not read the work item' do
+    let(:current_user) { create(:user) }
+
+    before do
+      post_graphql(query)
+    end
+
+    it 'returns an access error' do
+      expect(work_item_data).to be_nil
+      expect(graphql_errors).to contain_exactly(
+        hash_including('message' => ::Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
+      )
+    end
+  end
+
+  context 'when the work_items feature flag is disabled' do
+    before do
+      stub_feature_flags(work_items: false)
+    end
+
+    it 'returns nil' do
+      post_graphql(query)
+
+      expect(work_item_data).to be_nil
+    end
+  end
+end