diff --git a/Gemfile b/Gemfile
index 7280029654bcfa16f7d51a6ad3a96a1f7eabbdea..99dce3ba067852e08e203bbfccbc19bd2f07a2fe 100644
--- a/Gemfile
+++ b/Gemfile
@@ -84,6 +84,7 @@ gem 'rack-cors', '~> 1.0.0', require: 'rack/cors'
 gem 'graphql', '~> 1.8.0'
 gem 'graphiql-rails', '~> 1.4.10'
 gem 'apollo_upload_server', '~> 2.0.0.beta3'
+gem 'graphql-docs', '~> 1.6.0', group: [:development, :test]
 
 # Disable strong_params so that Mash does not respond to :permitted?
 gem 'hashie-forbidden_attributes'
diff --git a/Gemfile.lock b/Gemfile.lock
index 1f4705dd17342135f1146e63a03fd7e17c22f778..1a3b3b8e125f68a2a06dab80e77730dac9f3bdb6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -216,6 +216,8 @@ GEM
     excon (0.62.0)
     execjs (2.6.0)
     expression_parser (0.9.0)
+    extended-markdown-filter (0.6.0)
+      html-pipeline (~> 2.0)
     factory_bot (4.8.2)
       activesupport (>= 3.0.0)
     factory_bot_rails (4.8.2)
@@ -290,6 +292,7 @@ GEM
     fuubar (2.2.0)
       rspec-core (~> 3.0)
       ruby-progressbar (~> 1.4)
+    gemoji (3.0.1)
     gemojione (3.3.0)
       json
     get_process_mem (0.2.3)
@@ -370,6 +373,14 @@ GEM
       railties
       sprockets-rails
     graphql (1.8.1)
+    graphql-docs (1.6.0)
+      commonmarker (~> 0.16)
+      escape_utils (~> 1.2)
+      extended-markdown-filter (~> 0.4)
+      gemoji (~> 3.0)
+      graphql (~> 1.6)
+      html-pipeline (~> 2.8)
+      sass (~> 3.4)
     grpc (1.19.0)
       google-protobuf (~> 3.1)
       googleapis-common-protos-types (~> 1.0.0)
@@ -1118,6 +1129,7 @@ DEPENDENCIES
   grape_logging (~> 1.7)
   graphiql-rails (~> 1.4.10)
   graphql (~> 1.8.0)
+  graphql-docs (~> 1.6.0)
   grpc (~> 1.19.0)
   haml_lint (~> 0.31.0)
   hamlit (~> 2.8.8)
diff --git a/doc/api/graphql/index.md b/doc/api/graphql/index.md
index 4e4b9418e47fdc2bc903311c7bcd43564fda8296..bdc7c1959d25422b898d0002397cf71c5e175556 100644
--- a/doc/api/graphql/index.md
+++ b/doc/api/graphql/index.md
@@ -47,6 +47,12 @@ info about multiplexed queries is also available for
 [graphql-ruby](https://graphql-ruby.org/queries/multiplex.html) the
 library GitLab uses on the backend.
 
+## Reference
+
+GitLab's GraphQL reference [is available](reference/index.md).
+
+It is automatically generated from GitLab's GraphQL schema and embedded in a Markdown file.
+
 ## GraphiQL
 
 The API can be explored by using the GraphiQL IDE, it is available on your
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
new file mode 100644
index 0000000000000000000000000000000000000000..2d3bec4ff673bb6294befc0d57f246d91ba50d29
--- /dev/null
+++ b/doc/api/graphql/reference/index.md
@@ -0,0 +1,507 @@
+<!---
+  This documentation is auto generated by a script.
+
+  Please do not edit this file directly, check compile_docs task on lib/tasks/gitlab/graphql.rake.
+--->
+
+# GraphQL API Resources
+
+This documentation is self-generated based on GitLab current GraphQL schema.
+
+The API can be explored interactively using the [GraphiQL IDE](../index.md#graphiql).
+
+## Objects
+
+### AddAwardEmojiPayload
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `awardEmoji` | AwardEmoji | The award emoji after mutation |
+
+### AwardEmoji
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `name` | String! | The emoji name |
+| `description` | String! | The emoji description |
+| `unicode` | String! | The emoji in unicode |
+| `emoji` | String! | The emoji as an icon |
+| `unicodeVersion` | String! | The unicode version for this emoji |
+| `user` | User! | The user who awarded the emoji |
+
+### Blob
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `id` | ID! |  |
+| `name` | String! |  |
+| `type` | EntryType! |  |
+| `path` | String! |  |
+| `flatPath` | String! |  |
+| `webUrl` | String |  |
+| `lfsOid` | String |  |
+
+### Commit
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `id` | ID! |  |
+| `sha` | String! |  |
+| `title` | String |  |
+| `description` | String |  |
+| `message` | String |  |
+| `authoredDate` | Time |  |
+| `webUrl` | String! |  |
+| `author` | User |  |
+| `latestPipeline` | Pipeline | Latest pipeline for this commit |
+
+### DetailedStatus
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `group` | String! |  |
+| `icon` | String! |  |
+| `favicon` | String! |  |
+| `detailsPath` | String! |  |
+| `hasDetails` | Boolean! |  |
+| `label` | String! |  |
+| `text` | String! |  |
+| `tooltip` | String! |  |
+
+### DiffPosition
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `headSha` | String! | The sha of the head at the time the comment was made |
+| `baseSha` | String | The merge base of the branch the comment was made on |
+| `startSha` | String! | The sha of the branch being compared against |
+| `filePath` | String! | The path of the file that was changed |
+| `oldPath` | String | The path of the file on the start sha. |
+| `newPath` | String | The path of the file on the head sha. |
+| `positionType` | DiffPositionType! |  |
+| `oldLine` | Int | The line on start sha that was changed |
+| `newLine` | Int | The line on head sha that was changed |
+| `x` | Int | The X postion on which the comment was made |
+| `y` | Int | The Y position on which the comment was made |
+| `width` | Int | The total width of the image |
+| `height` | Int | The total height of the image |
+
+### Discussion
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `id` | ID! |  |
+| `createdAt` | Time! |  |
+
+### Group
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `id` | ID! |  |
+| `name` | String! |  |
+| `path` | String! |  |
+| `fullName` | String! |  |
+| `fullPath` | ID! |  |
+| `description` | String |  |
+| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
+| `visibility` | String |  |
+| `lfsEnabled` | Boolean |  |
+| `requestAccessEnabled` | Boolean |  |
+| `userPermissions` | GroupPermissions! | Permissions for the current user on the resource |
+| `webUrl` | String! |  |
+| `avatarUrl` | String |  |
+| `parent` | Group |  |
+
+### GroupPermissions
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `readGroup` | Boolean! | Whether or not a user can perform `read_group` on this resource |
+
+### Issue
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `userPermissions` | IssuePermissions! | Permissions for the current user on the resource |
+| `iid` | ID! |  |
+| `title` | String! |  |
+| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
+| `description` | String |  |
+| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
+| `state` | IssueState! |  |
+| `reference` | String! |  |
+| `author` | User! |  |
+| `milestone` | Milestone |  |
+| `dueDate` | Time |  |
+| `confidential` | Boolean! |  |
+| `discussionLocked` | Boolean! |  |
+| `upvotes` | Int! |  |
+| `downvotes` | Int! |  |
+| `userNotesCount` | Int! |  |
+| `webPath` | String! |  |
+| `webUrl` | String! |  |
+| `relativePosition` | Int |  |
+| `closedAt` | Time |  |
+| `createdAt` | Time! |  |
+| `updatedAt` | Time! |  |
+| `taskCompletionStatus` | TaskCompletionStatus! |  |
+
+### IssuePermissions
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `readIssue` | Boolean! | Whether or not a user can perform `read_issue` on this resource |
+| `adminIssue` | Boolean! | Whether or not a user can perform `admin_issue` on this resource |
+| `updateIssue` | Boolean! | Whether or not a user can perform `update_issue` on this resource |
+| `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource |
+| `reopenIssue` | Boolean! | Whether or not a user can perform `reopen_issue` on this resource |
+
+### Label
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `description` | String |  |
+| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
+| `title` | String! |  |
+| `color` | String! |  |
+| `textColor` | String! |  |
+
+### MergeRequest
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `userPermissions` | MergeRequestPermissions! | Permissions for the current user on the resource |
+| `id` | ID! |  |
+| `iid` | String! |  |
+| `title` | String! |  |
+| `titleHtml` | String | The GitLab Flavored Markdown rendering of `title` |
+| `description` | String |  |
+| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
+| `state` | MergeRequestState! |  |
+| `createdAt` | Time! |  |
+| `updatedAt` | Time! |  |
+| `sourceProject` | Project |  |
+| `targetProject` | Project! |  |
+| `project` | Project! |  |
+| `projectId` | Int! |  |
+| `sourceProjectId` | Int |  |
+| `targetProjectId` | Int! |  |
+| `sourceBranch` | String! |  |
+| `targetBranch` | String! |  |
+| `workInProgress` | Boolean! |  |
+| `mergeWhenPipelineSucceeds` | Boolean |  |
+| `diffHeadSha` | String |  |
+| `mergeCommitSha` | String |  |
+| `userNotesCount` | Int |  |
+| `shouldRemoveSourceBranch` | Boolean |  |
+| `forceRemoveSourceBranch` | Boolean |  |
+| `mergeStatus` | String |  |
+| `inProgressMergeCommitSha` | String |  |
+| `mergeError` | String |  |
+| `allowCollaboration` | Boolean |  |
+| `shouldBeRebased` | Boolean! |  |
+| `rebaseCommitSha` | String |  |
+| `rebaseInProgress` | Boolean! |  |
+| `mergeCommitMessage` | String |  |
+| `defaultMergeCommitMessage` | String |  |
+| `mergeOngoing` | Boolean! |  |
+| `sourceBranchExists` | Boolean! |  |
+| `mergeableDiscussionsState` | Boolean |  |
+| `webUrl` | String |  |
+| `upvotes` | Int! |  |
+| `downvotes` | Int! |  |
+| `subscribed` | Boolean! |  |
+| `headPipeline` | Pipeline |  |
+| `taskCompletionStatus` | TaskCompletionStatus! |  |
+
+### MergeRequestPermissions
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `readMergeRequest` | Boolean! | Whether or not a user can perform `read_merge_request` on this resource |
+| `adminMergeRequest` | Boolean! | Whether or not a user can perform `admin_merge_request` on this resource |
+| `updateMergeRequest` | Boolean! | Whether or not a user can perform `update_merge_request` on this resource |
+| `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource |
+| `pushToSourceBranch` | Boolean! | Whether or not a user can perform `push_to_source_branch` on this resource |
+| `removeSourceBranch` | Boolean! | Whether or not a user can perform `remove_source_branch` on this resource |
+| `cherryPickOnCurrentMergeRequest` | Boolean! | Whether or not a user can perform `cherry_pick_on_current_merge_request` on this resource |
+| `revertOnCurrentMergeRequest` | Boolean! | Whether or not a user can perform `revert_on_current_merge_request` on this resource |
+
+### MergeRequestSetWipPayload
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `mergeRequest` | MergeRequest | The merge request after mutation |
+
+### Metadata
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `version` | String! |  |
+| `revision` | String! |  |
+
+### Milestone
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `description` | String |  |
+| `title` | String! |  |
+| `state` | String! |  |
+| `dueDate` | Time |  |
+| `startDate` | Time |  |
+| `createdAt` | Time! |  |
+| `updatedAt` | Time! |  |
+
+### Namespace
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `id` | ID! |  |
+| `name` | String! |  |
+| `path` | String! |  |
+| `fullName` | String! |  |
+| `fullPath` | ID! |  |
+| `description` | String |  |
+| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
+| `visibility` | String |  |
+| `lfsEnabled` | Boolean |  |
+| `requestAccessEnabled` | Boolean |  |
+
+### Note
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `userPermissions` | NotePermissions! | Permissions for the current user on the resource |
+| `id` | ID! |  |
+| `project` | Project | The project this note is associated to |
+| `author` | User! | The user who wrote this note |
+| `resolvedBy` | User | The user that resolved the discussion |
+| `system` | Boolean! | Whether or not this note was created by the system or by a user |
+| `body` | String! | The content note itself |
+| `bodyHtml` | String | The GitLab Flavored Markdown rendering of `note` |
+| `createdAt` | Time! |  |
+| `updatedAt` | Time! |  |
+| `discussion` | Discussion | The discussion this note is a part of |
+| `resolvable` | Boolean! |  |
+| `resolvedAt` | Time | The time the discussion was resolved |
+| `position` | DiffPosition | The position of this note on a diff |
+
+### NotePermissions
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `readNote` | Boolean! | Whether or not a user can perform `read_note` on this resource |
+| `createNote` | Boolean! | Whether or not a user can perform `create_note` on this resource |
+| `adminNote` | Boolean! | Whether or not a user can perform `admin_note` on this resource |
+| `resolveNote` | Boolean! | Whether or not a user can perform `resolve_note` on this resource |
+| `awardEmoji` | Boolean! | Whether or not a user can perform `award_emoji` on this resource |
+
+### PageInfo
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `hasNextPage` | Boolean! | When paginating forwards, are there more items? |
+| `hasPreviousPage` | Boolean! | When paginating backwards, are there more items? |
+| `startCursor` | String | When paginating backwards, the cursor to continue. |
+| `endCursor` | String | When paginating forwards, the cursor to continue. |
+
+### Pipeline
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `userPermissions` | PipelinePermissions! | Permissions for the current user on the resource |
+| `id` | ID! |  |
+| `iid` | String! |  |
+| `sha` | String! |  |
+| `beforeSha` | String |  |
+| `status` | PipelineStatusEnum! |  |
+| `detailedStatus` | DetailedStatus! |  |
+| `duration` | Int | Duration of the pipeline in seconds |
+| `coverage` | Float | Coverage percentage |
+| `createdAt` | Time! |  |
+| `updatedAt` | Time! |  |
+| `startedAt` | Time |  |
+| `finishedAt` | Time |  |
+| `committedAt` | Time |  |
+
+### PipelinePermissions
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `updatePipeline` | Boolean! | Whether or not a user can perform `update_pipeline` on this resource |
+| `adminPipeline` | Boolean! | Whether or not a user can perform `admin_pipeline` on this resource |
+| `destroyPipeline` | Boolean! | Whether or not a user can perform `destroy_pipeline` on this resource |
+
+### Project
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `userPermissions` | ProjectPermissions! | Permissions for the current user on the resource |
+| `id` | ID! |  |
+| `fullPath` | ID! |  |
+| `path` | String! |  |
+| `nameWithNamespace` | String! |  |
+| `name` | String! |  |
+| `description` | String |  |
+| `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` |
+| `tagList` | String |  |
+| `sshUrlToRepo` | String |  |
+| `httpUrlToRepo` | String |  |
+| `webUrl` | String |  |
+| `starCount` | Int! |  |
+| `forksCount` | Int! |  |
+| `createdAt` | Time |  |
+| `lastActivityAt` | Time |  |
+| `archived` | Boolean |  |
+| `visibility` | String |  |
+| `containerRegistryEnabled` | Boolean |  |
+| `sharedRunnersEnabled` | Boolean |  |
+| `lfsEnabled` | Boolean |  |
+| `mergeRequestsFfOnlyEnabled` | Boolean |  |
+| `avatarUrl` | String |  |
+| `issuesEnabled` | Boolean |  |
+| `mergeRequestsEnabled` | Boolean |  |
+| `wikiEnabled` | Boolean |  |
+| `snippetsEnabled` | Boolean |  |
+| `jobsEnabled` | Boolean |  |
+| `publicJobs` | Boolean |  |
+| `openIssuesCount` | Int |  |
+| `importStatus` | String |  |
+| `onlyAllowMergeIfPipelineSucceeds` | Boolean |  |
+| `requestAccessEnabled` | Boolean |  |
+| `onlyAllowMergeIfAllDiscussionsAreResolved` | Boolean |  |
+| `printingMergeRequestLinkEnabled` | Boolean |  |
+| `namespace` | Namespace |  |
+| `group` | Group |  |
+| `statistics` | ProjectStatistics |  |
+| `repository` | Repository |  |
+| `mergeRequest` | MergeRequest |  |
+| `issue` | Issue |  |
+
+### ProjectPermissions
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `changeNamespace` | Boolean! | Whether or not a user can perform `change_namespace` on this resource |
+| `changeVisibilityLevel` | Boolean! | Whether or not a user can perform `change_visibility_level` on this resource |
+| `renameProject` | Boolean! | Whether or not a user can perform `rename_project` on this resource |
+| `removeProject` | Boolean! | Whether or not a user can perform `remove_project` on this resource |
+| `archiveProject` | Boolean! | Whether or not a user can perform `archive_project` on this resource |
+| `removeForkProject` | Boolean! | Whether or not a user can perform `remove_fork_project` on this resource |
+| `removePages` | Boolean! | Whether or not a user can perform `remove_pages` on this resource |
+| `readProject` | Boolean! | Whether or not a user can perform `read_project` on this resource |
+| `createMergeRequestIn` | Boolean! | Whether or not a user can perform `create_merge_request_in` on this resource |
+| `readWiki` | Boolean! | Whether or not a user can perform `read_wiki` on this resource |
+| `readProjectMember` | Boolean! | Whether or not a user can perform `read_project_member` on this resource |
+| `createIssue` | Boolean! | Whether or not a user can perform `create_issue` on this resource |
+| `uploadFile` | Boolean! | Whether or not a user can perform `upload_file` on this resource |
+| `readCycleAnalytics` | Boolean! | Whether or not a user can perform `read_cycle_analytics` on this resource |
+| `downloadCode` | Boolean! | Whether or not a user can perform `download_code` on this resource |
+| `downloadWikiCode` | Boolean! | Whether or not a user can perform `download_wiki_code` on this resource |
+| `forkProject` | Boolean! | Whether or not a user can perform `fork_project` on this resource |
+| `createProjectSnippet` | Boolean! | Whether or not a user can perform `create_project_snippet` on this resource |
+| `readCommitStatus` | Boolean! | Whether or not a user can perform `read_commit_status` on this resource |
+| `requestAccess` | Boolean! | Whether or not a user can perform `request_access` on this resource |
+| `createPipeline` | Boolean! | Whether or not a user can perform `create_pipeline` on this resource |
+| `createPipelineSchedule` | Boolean! | Whether or not a user can perform `create_pipeline_schedule` on this resource |
+| `createMergeRequestFrom` | Boolean! | Whether or not a user can perform `create_merge_request_from` on this resource |
+| `createWiki` | Boolean! | Whether or not a user can perform `create_wiki` on this resource |
+| `pushCode` | Boolean! | Whether or not a user can perform `push_code` on this resource |
+| `createDeployment` | Boolean! | Whether or not a user can perform `create_deployment` on this resource |
+| `pushToDeleteProtectedBranch` | Boolean! | Whether or not a user can perform `push_to_delete_protected_branch` on this resource |
+| `adminWiki` | Boolean! | Whether or not a user can perform `admin_wiki` on this resource |
+| `adminProject` | Boolean! | Whether or not a user can perform `admin_project` on this resource |
+| `updatePages` | Boolean! | Whether or not a user can perform `update_pages` on this resource |
+| `adminRemoteMirror` | Boolean! | Whether or not a user can perform `admin_remote_mirror` on this resource |
+| `createLabel` | Boolean! | Whether or not a user can perform `create_label` on this resource |
+| `updateWiki` | Boolean! | Whether or not a user can perform `update_wiki` on this resource |
+| `destroyWiki` | Boolean! | Whether or not a user can perform `destroy_wiki` on this resource |
+| `createPages` | Boolean! | Whether or not a user can perform `create_pages` on this resource |
+| `destroyPages` | Boolean! | Whether or not a user can perform `destroy_pages` on this resource |
+| `readPagesContent` | Boolean! | Whether or not a user can perform `read_pages_content` on this resource |
+
+### ProjectStatistics
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `commitCount` | Int! |  |
+| `storageSize` | Int! |  |
+| `repositorySize` | Int! |  |
+| `lfsObjectsSize` | Int! |  |
+| `buildArtifactsSize` | Int! |  |
+| `packagesSize` | Int! |  |
+| `wikiSize` | Int |  |
+
+### RemoveAwardEmojiPayload
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `awardEmoji` | AwardEmoji | The award emoji after mutation |
+
+### Repository
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `rootRef` | String |  |
+| `empty` | Boolean! |  |
+| `exists` | Boolean! |  |
+| `tree` | Tree |  |
+
+### Submodule
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `id` | ID! |  |
+| `name` | String! |  |
+| `type` | EntryType! |  |
+| `path` | String! |  |
+| `flatPath` | String! |  |
+
+### TaskCompletionStatus
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `count` | Int! |  |
+| `completedCount` | Int! |  |
+
+### ToggleAwardEmojiPayload
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
+| `errors` | String! => Array | Reasons why the mutation failed. |
+| `awardEmoji` | AwardEmoji | The award emoji after mutation |
+| `toggledOn` | Boolean! | True when the emoji was awarded, false when it was removed |
+
+### Tree
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `lastCommit` | Commit |  |
+
+### TreeEntry
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `id` | ID! |  |
+| `name` | String! |  |
+| `type` | EntryType! |  |
+| `path` | String! |  |
+| `flatPath` | String! |  |
+| `webUrl` | String |  |
+
+### User
+
+| Name  | Type  | Description |
+| ---   |  ---- | ----------  |
+| `name` | String! |  |
+| `username` | String! |  |
+| `avatarUrl` | String! |  |
+| `webUrl` | String! |  |
+
diff --git a/lib/gitlab/graphql/docs/helper.rb b/lib/gitlab/graphql/docs/helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..ac2a78c0f284387a9e4be43154f2cfc2e61dbfa2
--- /dev/null
+++ b/lib/gitlab/graphql/docs/helper.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+return if Rails.env.production?
+
+module Gitlab
+  module Graphql
+    module Docs
+      # Helper with functions to be used by HAML templates
+      # This includes graphql-docs gem helpers class.
+      # You can check the included module on: https://github.com/gjtorikian/graphql-docs/blob/v1.6.0/lib/graphql-docs/helpers.rb
+      module Helper
+        include GraphQLDocs::Helpers
+
+        def auto_generated_comment
+          <<-MD.strip_heredoc
+            <!---
+              This documentation is auto generated by a script.
+
+              Please do not edit this file directly, check compile_docs task on lib/tasks/gitlab/graphql.rake.
+            --->
+          MD
+        end
+
+        # Some fields types are arrays of other types and are displayed
+        # on docs wrapped in square brackets, for example: [String!].
+        # This makes GitLab docs renderer thinks they are links so here
+        # we change them to be rendered as: String! => Array.
+        def render_field_type(type)
+          array_type = type[/\[(.+)\]/, 1]
+
+          if array_type
+            "#{array_type} => Array"
+          else
+            type
+          end
+        end
+
+        # We are ignoring connections and built in types for now,
+        # they should be added when queries are generated.
+        def objects
+          graphql_object_types.select do |object_type|
+            !object_type[:name]["Connection"] &&
+              !object_type[:name]["Edge"] &&
+              !object_type[:name]["__"]
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/graphql/docs/renderer.rb b/lib/gitlab/graphql/docs/renderer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f47a372aa19ef0b80fad07154ebacf03c6c53f47
--- /dev/null
+++ b/lib/gitlab/graphql/docs/renderer.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+return if Rails.env.production?
+
+module Gitlab
+  module Graphql
+    module Docs
+      # Gitlab renderer for graphql-docs.
+      # Uses HAML templates to parse markdown and generate .md files.
+      # It uses graphql-docs helpers and schema parser, more information in https://github.com/gjtorikian/graphql-docs.
+      #
+      # Arguments:
+      #   schema - the GraphQL schema defition. For GitLab should be: GitlabSchema.graphql_definition
+      #   output_dir: The folder where the markdown files will be saved
+      #   template: The path of the haml template to be parsed
+      class Renderer
+        include Gitlab::Graphql::Docs::Helper
+
+        def initialize(schema, output_dir:, template:)
+          @output_dir = output_dir
+          @template = template
+          @layout = Haml::Engine.new(File.read(template))
+          @parsed_schema = GraphQLDocs::Parser.new(schema, {}).parse
+        end
+
+        def render
+          contents = @layout.render(self)
+
+          write_file(contents)
+        end
+
+        private
+
+        def write_file(contents)
+          filename = File.join(@output_dir, 'index.md')
+
+          FileUtils.mkdir_p(@output_dir)
+          File.write(filename, contents)
+        end
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/graphql/docs/templates/default.md.haml b/lib/gitlab/graphql/docs/templates/default.md.haml
new file mode 100644
index 0000000000000000000000000000000000000000..cc22d43ab4f844549912d6a398fb1d8379cf1ba0
--- /dev/null
+++ b/lib/gitlab/graphql/docs/templates/default.md.haml
@@ -0,0 +1,25 @@
+-# haml-lint:disable UnnecessaryStringOutput
+
+= auto_generated_comment
+
+:plain
+  # GraphQL API Resources
+
+  This documentation is self-generated based on GitLab current GraphQL schema.
+
+  The API can be explored interactively using the [GraphiQL IDE](../index.md#graphiql).
+
+  ## Objects
+\
+- objects.each do |type|
+  - unless type[:fields].empty?
+    = "### #{type[:name]}"
+    \
+    ~ "| Name  | Type  | Description |"
+    ~ "| ---   |  ---- | ----------  |"
+    - type[:fields].each do |field|
+      = "| `#{field[:name]}` | #{render_field_type(field[:type][:info])} | #{field[:description]} |"
+    \
+
+
+
diff --git a/lib/tasks/gitlab/graphql.rake b/lib/tasks/gitlab/graphql.rake
new file mode 100644
index 0000000000000000000000000000000000000000..c53d55ceea2bf349acb034b776a28dee227d3c98
--- /dev/null
+++ b/lib/tasks/gitlab/graphql.rake
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+return if Rails.env.production?
+
+namespace :gitlab do
+  OUTPUT_DIR = Rails.root.join("doc/api/graphql/reference").freeze
+  TEMPLATES_DIR = 'lib/gitlab/graphql/docs/templates/'.freeze
+
+  namespace :graphql do
+    desc 'GitLab | Generate GraphQL docs'
+    task compile_docs: :environment do
+      renderer = Gitlab::Graphql::Docs::Renderer.new(GitlabSchema.graphql_definition, render_options)
+
+      renderer.render
+
+      puts "Documentation compiled."
+    end
+  end
+end
+
+def render_options
+  {
+    output_dir: OUTPUT_DIR,
+    template: Rails.root.join(TEMPLATES_DIR, 'default.md.haml')
+  }
+end