diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index 07cc889b1227f00cba6b2bb2a1c35a0ac25520a0..1d081573f01a39c6264429e5f9282d14354cd82a 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -566,3 +566,16 @@ This task clones the remote repository, recursively walks the file system lookin
 ending in `.pub`, parses those files as SSH public keys, and then adds the public key fingerprints
 to `output_file`. The contents of `config/security/banned_ssh_keys.yml` is read by GitLab and kept
 in memory. It is not recommended to increase the size of this file beyond 1 megabyte in size.
+
+## Output current navigation structure to YAML
+
+_This task relies on your current environment setup (licensing, feature flags, projects/groups), so output may vary from run-to-run or environment-to-environment. We may look to standardize output in a future iteration._
+
+Product, UX, and tech writing need a way to audit the entire GitLab navigation,
+yet may not be comfortable directly reviewing the code in `lib/sidebars`. You
+can dump the entire nav structure to YAML via the `gitlab:nav:dump_structure`
+Rake task:
+
+```shell
+bundle exec rake gitlab:nav:dump_structure
+```
diff --git a/ee/lib/tasks/gitlab/nav/dump_structure.rake b/ee/lib/tasks/gitlab/nav/dump_structure.rake
new file mode 100644
index 0000000000000000000000000000000000000000..841fe18d1d07c04af8b4a4e03b7a15d7e2c80eda
--- /dev/null
+++ b/ee/lib/tasks/gitlab/nav/dump_structure.rake
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+return if Rails.env.production?
+
+namespace :gitlab do
+  namespace :nav do
+    desc "GitLab | Nav | Dump the complete navigation structure for all navigation contexts"
+    task :dump_structure, [] => :gitlab_environment do
+      dumper = Tasks::Gitlab::Nav::DumpStructure.new
+      puts dumper.dump
+    end
+  end
+end
diff --git a/ee/lib/tasks/gitlab/nav/dump_structure.rb b/ee/lib/tasks/gitlab/nav/dump_structure.rb
new file mode 100644
index 0000000000000000000000000000000000000000..42016802b1bbf96c252780ec25b64134aa996909
--- /dev/null
+++ b/ee/lib/tasks/gitlab/nav/dump_structure.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+module Tasks
+  module Gitlab
+    module Nav
+      class DumpStructure
+        attr_accessor :context_defaults
+
+        def initialize
+          @context_defaults = {
+            current_user: User.first,
+            is_super_sidebar: true,
+
+            # Turn features on that impact the list of items rendered
+            can_view_pipeline_editor: true,
+            learn_gitlab_enabled: true,
+            show_discover_group_security: true,
+            show_discover_project_security: true,
+            show_security_dashboard: true,
+
+            # Turn features off that do not add/remove items
+            show_cluster_hint: false,
+            show_promotions: false,
+
+            current_ref: 'master'
+          }
+        end
+
+        def panels
+          panels = []
+          panels << Sidebars::UserProfile::Panel.new(Sidebars::Context.new(
+            container: User.first,
+            **@context_defaults
+          ))
+          panels << Sidebars::UserSettings::Panel.new(Sidebars::Context.new(
+            container: User.first,
+            **@context_defaults
+          ))
+          panels << Sidebars::YourWork::Panel.new(Sidebars::Context.new(
+            container: User.first,
+            **@context_defaults
+          ))
+          panels << Sidebars::Projects::SuperSidebarPanel.new(Sidebars::Projects::Context.new(
+            container: Project.first,
+            **@context_defaults
+          ))
+          panels << Sidebars::Groups::SuperSidebarPanel.new(Sidebars::Groups::Context.new(
+            container: Group.first,
+            **@context_defaults
+          ))
+          panels << Sidebars::Organizations::Panel.new(Sidebars::Context.new(
+            container: Organizations::Organization.first,
+            **@context_defaults
+          ))
+          panels << Sidebars::Admin::Panel.new(Sidebars::Context.new(
+            container: nil,
+            **@context_defaults
+          ))
+          panels << Sidebars::Explore::Panel.new(Sidebars::Context.new(
+            container: nil,
+            **@context_defaults
+          ))
+
+          panels
+        end
+
+        def current_time
+          Time.now.utc.iso8601
+        end
+
+        def current_sha
+          `git rev-parse --short HEAD`.strip
+        end
+
+        def dump
+          contexts = panels.map do |panel|
+            {
+              title: panel.aria_label,
+              items: panel.super_sidebar_menu_items
+            }
+          end
+
+          # Recurse through structure to drop info we don't need
+          clean_keys!(contexts)
+
+          YAML.dump({
+            generated_at: current_time,
+            commit_sha: current_sha,
+            contexts: contexts
+          }.deep_stringify_keys)
+        end
+
+        private
+
+        def clean_keys!(entries)
+          entries.each do |entry|
+            clean_keys!(entry[:items]) if entry[:items]
+
+            entry[:id] = entry[:id].to_s if entry[:id]
+            entry.slice!(:id, :title, :icon, :link, :items)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/ee/spec/tasks/gitlab/nav/dump_structure_spec.rb b/ee/spec/tasks/gitlab/nav/dump_structure_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..cfded2d1130df4b5097e8b1cce33f96969bbd95e
--- /dev/null
+++ b/ee/spec/tasks/gitlab/nav/dump_structure_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'gitlab:nav:dump_structure', :silence_stdout, feature_category: :navigation do
+  let!(:user) { create(:user) }
+
+  before do
+    # Build out scaffold records required for rake task
+    create(:project)
+    create(:group)
+    create(:organization)
+
+    Rake.application.rake_require 'tasks/gitlab/nav/dump_structure'
+  end
+
+  it 'outputs YAML describing the current nav structure' do
+    # Sample items that _hopefully_ won't change very often.
+    expected = {
+      "generated_at" => an_instance_of(String),
+      "commit_sha" => an_instance_of(String),
+      "contexts" => a_collection_including(a_hash_including({
+        "title" => "User profile navigation",
+        "items" => a_collection_including(a_hash_including({
+          "id" => "activity_menu",
+          "title" => "Activity",
+          "icon" => "history",
+          "link" => "/users/#{user.username}/activity"
+        }))
+      }))
+    }
+    expect(YAML).to receive(:dump).with(expected)
+
+    run_rake_task('gitlab:nav:dump_structure')
+  end
+end