diff --git a/app/graphql/types/milestone_type.rb b/app/graphql/types/milestone_type.rb
index 447528917f0428ebd48f3419dcdcc0be9548ea69..79bc7dcb17c7b56fdf66f86e07fe4b521ad886b5 100644
--- a/app/graphql/types/milestone_type.rb
+++ b/app/graphql/types/milestone_type.rb
@@ -29,6 +29,9 @@ class MilestoneType < BaseObject
     field :expired, GraphQL::Types::Boolean, null: false,
                                              description: 'Expired state of the milestone (a milestone is expired when the due date is past the current date). Defaults to `false` when due date has not been set.'
 
+    field :upcoming, GraphQL::Types::Boolean, null: false,
+                                              description: 'Upcoming state of the milestone (a milestone is upcoming when the start date is in the future). Defaults to `false` when start date has not been set.'
+
     field :web_path, GraphQL::Types::String, null: false, method: :milestone_path,
                                              description: 'Web path of the milestone.'
 
@@ -44,10 +47,14 @@ class MilestoneType < BaseObject
     field :updated_at, Types::TimeType, null: false,
                                         description: 'Timestamp of last milestone update.'
 
+    field :project, Types::ProjectType, null: true, description: 'Project of the milestone.'
+
     field :project_milestone, GraphQL::Types::Boolean, null: false,
                                                        description: 'Indicates if milestone is at project level.',
                                                        method: :project_milestone?
 
+    field :group, Types::GroupType, null: true, description: 'Group of the milestone.'
+
     field :group_milestone, GraphQL::Types::Boolean, null: false,
                                                      description: 'Indicates if milestone is at group level.',
                                                      method: :group_milestone?
diff --git a/app/models/concerns/milestoneish.rb b/app/models/concerns/milestoneish.rb
index 3d9e09acf44e0fd479a6dfcbd9d9c852b261d352..33d11936c6e7d5653942934c35e21497fb9a6d60 100644
--- a/app/models/concerns/milestoneish.rb
+++ b/app/models/concerns/milestoneish.rb
@@ -88,6 +88,10 @@ def upcoming?
     start_date && start_date.future?
   end
 
+  def upcoming
+    upcoming? || false
+  end
+
   def expires_at
     if due_date
       if due_date.past?
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index a0fbc616cb58c6c28db47724e8c4a15c0a3ebb71..26c59d84edb36a4901e6b439196edf4b7a956f63 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -24204,9 +24204,11 @@ Represents a milestone.
 | <a id="milestonedescription"></a>`description` | [`String`](#string) | Description of the milestone. |
 | <a id="milestoneduedate"></a>`dueDate` | [`Time`](#time) | Timestamp of the milestone due date. |
 | <a id="milestoneexpired"></a>`expired` | [`Boolean!`](#boolean) | Expired state of the milestone (a milestone is expired when the due date is past the current date). Defaults to `false` when due date has not been set. |
+| <a id="milestonegroup"></a>`group` | [`Group`](#group) | Group of the milestone. |
 | <a id="milestonegroupmilestone"></a>`groupMilestone` | [`Boolean!`](#boolean) | Indicates if milestone is at group level. |
 | <a id="milestoneid"></a>`id` | [`ID!`](#id) | ID of the milestone. |
 | <a id="milestoneiid"></a>`iid` | [`ID!`](#id) | Internal ID of the milestone. |
+| <a id="milestoneproject"></a>`project` | [`Project`](#project) | Project of the milestone. |
 | <a id="milestoneprojectmilestone"></a>`projectMilestone` | [`Boolean!`](#boolean) | Indicates if milestone is at project level. |
 | <a id="milestonereleases"></a>`releases` | [`ReleaseConnection`](#releaseconnection) | Releases associated with this milestone. (see [Connections](#connections)) |
 | <a id="milestonestartdate"></a>`startDate` | [`Time`](#time) | Timestamp of the milestone start date. |
@@ -24214,6 +24216,7 @@ Represents a milestone.
 | <a id="milestonestats"></a>`stats` | [`MilestoneStats`](#milestonestats) | Milestone statistics. |
 | <a id="milestonesubgroupmilestone"></a>`subgroupMilestone` | [`Boolean!`](#boolean) | Indicates if milestone is at subgroup level. |
 | <a id="milestonetitle"></a>`title` | [`String!`](#string) | Title of the milestone. |
+| <a id="milestoneupcoming"></a>`upcoming` | [`Boolean!`](#boolean) | Upcoming state of the milestone (a milestone is upcoming when the start date is in the future). Defaults to `false` when start date has not been set. |
 | <a id="milestoneupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of last milestone update. |
 | <a id="milestonewebpath"></a>`webPath` | [`String!`](#string) | Web path of the milestone. |
 
diff --git a/spec/graphql/types/milestone_type_spec.rb b/spec/graphql/types/milestone_type_spec.rb
index f00acb3f7cf76980fbeaa4049c008e334a4b6121..8eadc1ddd874460e3a0a85b16b8d65e1f378ba64 100644
--- a/spec/graphql/types/milestone_type_spec.rb
+++ b/spec/graphql/types/milestone_type_spec.rb
@@ -9,9 +9,9 @@
 
   it 'has the expected fields' do
     expected_fields = %w[
-      id iid title description state expired web_path
+      id iid title description state expired upcoming web_path
       due_date start_date created_at updated_at
-      project_milestone group_milestone subgroup_milestone
+      project project_milestone group group_milestone subgroup_milestone
       stats
     ]
 
diff --git a/spec/requests/api/graphql/milestone_spec.rb b/spec/requests/api/graphql/milestone_spec.rb
index 3c5f29f05293ab6abef7e819d99bb9fa1e95e217..a2c226a0fe6649b2217809bed5c44a83d395802a 100644
--- a/spec/requests/api/graphql/milestone_spec.rb
+++ b/spec/requests/api/graphql/milestone_spec.rb
@@ -40,7 +40,11 @@
   context 'when we post the query' do
     context 'and the project is private' do
       let(:query) do
-        graphql_query_for('milestone', { id: milestone.to_global_id.to_s }, all_graphql_fields_for('Milestone'))
+        graphql_query_for(
+          'milestone',
+          { id: milestone.to_global_id.to_s },
+          all_graphql_fields_for('Milestone', excluded: %w[project group])
+        )
       end
 
       subject { graphql_data['milestone'] }
@@ -55,6 +59,15 @@
 
           it_behaves_like 'returns the milestone successfully'
 
+          context 'when milestone has no dates' do
+            it 'returns upcoming and expired as false' do
+              expect(graphql_data_at(:milestone, :due_date)).to be_nil
+              expect(graphql_data_at(:milestone, :start_date)).to be_nil
+              expect(graphql_data_at(:milestone, :upcoming)).to be false
+              expect(graphql_data_at(:milestone, :expired)).to be false
+            end
+          end
+
           context 'when there are two milestones' do
             let_it_be(:milestone_b) { create(:milestone, project: project) }