diff --git a/app/components/version-list/row.hbs b/app/components/version-list/row.hbs
index 7446250208d..11ce1dcc151 100644
--- a/app/components/version-list/row.hbs
+++ b/app/components/version-list/row.hbs
@@ -128,6 +128,18 @@
         <menu.Item>
           <YankButton @version={{@version}} class="button-reset" local-class="menu-button" />
         </menu.Item>
+        <menu.Item>
+          <button
+            class="button-reset"
+            local-class="menu-button"
+            type="button"
+            disabled={{@version.rebuildDocsTask.isRunning}}
+            data-test-id="btn-rebuild-docs"
+            {{on 'click' (perform this.rebuildDocsTask)}}
+          >
+            Rebuild Docs
+          </button>
+        </menu.Item>
       </dd.Menu>
     </Dropdown>
   </PrivilegedAction>
diff --git a/app/components/version-list/row.js b/app/components/version-list/row.js
index 82ee537993c..15deed1253a 100644
--- a/app/components/version-list/row.js
+++ b/app/components/version-list/row.js
@@ -4,9 +4,12 @@ import { htmlSafe } from '@ember/template';
 import Component from '@glimmer/component';
 import { tracked } from '@glimmer/tracking';
 
+import { keepLatestTask } from 'ember-concurrency';
+
 import styles from './row.module.css';
 
 export default class VersionRow extends Component {
+  @service notifications;
   @service session;
 
   @tracked focused = false;
@@ -59,4 +62,16 @@ export default class VersionRow extends Component {
   @action setFocused(value) {
     this.focused = value;
   }
+
+  rebuildDocsTask = keepLatestTask(async () => {
+    let { version } = this.args;
+    try {
+      await version.rebuildDocs();
+      this.notifications.success('Docs rebuild task was enqueued successfully!');
+    } catch (error) {
+      let reason = error?.errors?.[0]?.detail ?? 'Failed to equeue docs rebuild task.';
+      let msg = `Error: ${reason}`;
+      this.notifications.error(msg);
+    }
+  });
 }
diff --git a/app/models/version.js b/app/models/version.js
index 1a89cbf1706..c07e781e1ed 100644
--- a/app/models/version.js
+++ b/app/models/version.js
@@ -200,4 +200,8 @@ export default class Version extends Model {
     this.store.pushPayload(payload);
     await waitForPromise(this.releaseTracks.refreshTask.perform(this.crateName, false));
   });
+
+  async rebuildDocs() {
+    return await waitForPromise(apiAction(this, { method: 'POST', path: 'rebuild_docs' }));
+  }
 }
diff --git a/e2e/acceptance/versions.spec.ts b/e2e/acceptance/versions.spec.ts
index c61d297a6b0..c895a34f7b6 100644
--- a/e2e/acceptance/versions.spec.ts
+++ b/e2e/acceptance/versions.spec.ts
@@ -68,4 +68,31 @@ test.describe('Acceptance | crate versions page', { tag: '@acceptance' }, () =>
     await expect(v020).not.toHaveClass(/.*latest/);
     await expect(v020).not.toHaveClass(/.yanked/);
   });
+
+  test('triggers a rebuild for crate documentation', async ({ page, msw }) => {
+    let user = msw.db.user.create();
+    await msw.authenticateAs(user);
+
+    let crate = msw.db.crate.create({ name: 'nanomsg' });
+    msw.db.crateOwnership.create({ crate, user });
+
+    msw.db.version.create({ crate, num: '0.1.0', created_at: '2017-01-01' });
+    msw.db.version.create({ crate, num: '0.2.0', created_at: '2018-01-01' });
+    msw.db.version.create({ crate, num: '0.3.0', created_at: '2019-01-01', rust_version: '1.69' });
+    msw.db.version.create({ crate, num: '0.2.1', created_at: '2020-01-01' });
+
+    await page.goto('/crates/nanomsg/versions');
+    await expect(page).toHaveURL('/crates/nanomsg/versions');
+
+    await expect(page.locator('[data-test-version]')).toHaveCount(4);
+    let versions = await page.locator('[data-test-version]').evaluateAll(el => el.map(it => it.dataset.testVersion));
+    expect(versions).toEqual(['0.2.1', '0.3.0', '0.2.0', '0.1.0']);
+
+    let v021 = page.locator('[data-test-version="0.2.1"]');
+    await v021.locator('[data-test-actions-toggle]').click();
+    await v021.getByRole('button', { name: 'Rebuild Docs' }).click();
+
+    let message = 'Docs rebuild task was enqueued successfully!';
+    await expect(page.locator('[data-test-notification-message="success"]')).toHaveText(message);
+  });
 });
diff --git a/tests/acceptance/versions-test.js b/tests/acceptance/versions-test.js
index cff0df2e9b2..5cc09f13169 100644
--- a/tests/acceptance/versions-test.js
+++ b/tests/acceptance/versions-test.js
@@ -81,4 +81,29 @@ module('Acceptance | crate versions page', function (hooks) {
       .hasNoClass(/.*latest/)
       .hasNoClass(/.yanked/);
   });
+
+  test('triggers a rebuild for crate documentation', async function (assert) {
+    let user = this.db.user.create();
+    this.authenticateAs(user);
+
+    let crate = this.db.crate.create({ name: 'nanomsg' });
+    this.db.crateOwnership.create({ crate, user });
+
+    this.db.version.create({ crate, num: '0.1.0', created_at: '2017-01-01' });
+    this.db.version.create({ crate, num: '0.2.0', created_at: '2018-01-01' });
+    this.db.version.create({ crate, num: '0.3.0', created_at: '2019-01-01', rust_version: '1.69' });
+    this.db.version.create({ crate, num: '0.2.1', created_at: '2020-01-01' });
+
+    await visit('/crates/nanomsg/versions');
+    assert.strictEqual(currentURL(), '/crates/nanomsg/versions');
+
+    let versions = findAll('[data-test-version]').map(it => it.dataset.testVersion);
+    assert.deepEqual(versions, ['0.2.1', '0.3.0', '0.2.0', '0.1.0']);
+
+    await click('[data-test-version="0.2.1"] [data-test-actions-toggle]');
+    await click('[data-test-version="0.2.1"] [data-test-id="btn-rebuild-docs"]');
+
+    let message = 'Docs rebuild task was enqueued successfully!';
+    assert.dom('[data-test-notification-message="success"]').hasText(message);
+  });
 });