diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js
index 76d9b18b777d96b0d0c784221d0de6f038949c93..2d9ffda06d040f996b53e5d8afa9cac0ba40a1b5 100644
--- a/app/assets/javascripts/blob_edit/blob_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_bundle.js
@@ -69,6 +69,7 @@ export default () => {
     const currentAction = $('.js-file-title').data('currentAction');
     const projectId = editBlobForm.data('project-id');
     const isMarkdown = editBlobForm.data('is-markdown');
+    const previewMarkdownPath = editBlobForm.data('previewMarkdownPath');
     const commitButton = $('.js-commit-button');
     const cancelLink = $('.btn.btn-cancel');
 
@@ -80,6 +81,7 @@ export default () => {
           currentAction,
           projectId,
           isMarkdown,
+          previewMarkdownPath,
         });
         initPopovers();
         initCodeQualityWalkthroughStep();
diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js
index e068910c62687829e92e90295abf4e45126b380e..118cef59d5a01b114af25d705485da129fd04cbb 100644
--- a/app/assets/javascripts/blob_edit/edit_blob.js
+++ b/app/assets/javascripts/blob_edit/edit_blob.js
@@ -11,7 +11,7 @@ import { BLOB_EDITOR_ERROR, BLOB_PREVIEW_ERROR } from './constants';
 
 export default class EditBlob {
   // The options object has:
-  // assetsPath, filePath, currentAction, projectId, isMarkdown
+  // assetsPath, filePath, currentAction, projectId, isMarkdown, previewMarkdownPath
   constructor(options) {
     this.options = options;
     this.configureMonacoEditor();
@@ -30,7 +30,10 @@ export default class EditBlob {
     import('~/editor/extensions/source_editor_markdown_ext')
       .then(({ EditorMarkdownExtension: MarkdownExtension } = {}) => {
         this.editor.use(
-          new MarkdownExtension({ instance: this.editor, projectPath: this.options.projectPath }),
+          new MarkdownExtension({
+            instance: this.editor,
+            previewMarkdownPath: this.options.previewMarkdownPath,
+          }),
         );
         this.hasMarkdownExtension = true;
         addEditorMarkdownListeners(this.editor);
diff --git a/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js b/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
index 76e009164f70f27eeb3ad7d7a168827848e71d2b..57de21c933ef66b1ab3a8800e43dd21d0d5cf40a 100644
--- a/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
+++ b/app/assets/javascripts/editor/extensions/source_editor_markdown_ext.js
@@ -14,17 +14,9 @@ import {
 } from '../constants';
 import { SourceEditorExtension } from './source_editor_extension_base';
 
-const getPreview = (text, projectPath = '') => {
-  let url;
-
-  if (projectPath) {
-    url = `/${projectPath}/preview_markdown`;
-  } else {
-    const { group, project } = document.body.dataset;
-    url = `/${group}/${project}/preview_markdown`;
-  }
+const getPreview = (text, previewMarkdownPath) => {
   return axios
-    .post(url, {
+    .post(previewMarkdownPath, {
       text,
     })
     .then(({ data }) => {
@@ -43,10 +35,10 @@ const setupDomElement = ({ injectToEl = null } = {}) => {
 };
 
 export class EditorMarkdownExtension extends SourceEditorExtension {
-  constructor({ instance, projectPath, ...args } = {}) {
+  constructor({ instance, previewMarkdownPath, ...args } = {}) {
     super({ instance, ...args });
     Object.assign(instance, {
-      projectPath,
+      previewMarkdownPath,
       preview: {
         el: undefined,
         action: undefined,
@@ -112,7 +104,7 @@ export class EditorMarkdownExtension extends SourceEditorExtension {
 
   fetchPreview() {
     const { el: previewEl } = this.preview;
-    getPreview(this.getValue(), this.projectPath)
+    getPreview(this.getValue(), this.previewMarkdownPath)
       .then((data) => {
         previewEl.innerHTML = sanitize(data);
         syntaxHighlight(previewEl.querySelectorAll('.js-syntax-highlight'));
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index 2f990280367f8c662b33ffb68ea6126f95b5319d..2bf99550bf22908f534fdc0c0861c7acfd437833 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -79,6 +79,7 @@ export default {
       'editorTheme',
       'entries',
       'currentProjectId',
+      'previewMarkdownPath',
     ]),
     ...mapGetters([
       'getAlert',
@@ -314,14 +315,15 @@ export default {
 
         if (
           this.fileType === MARKDOWN_FILE_TYPE &&
-          this.editor?.getEditorType() === EDITOR_TYPE_CODE
+          this.editor?.getEditorType() === EDITOR_TYPE_CODE &&
+          this.previewMarkdownPath
         ) {
           import('~/editor/extensions/source_editor_markdown_ext')
             .then(({ EditorMarkdownExtension: MarkdownExtension } = {}) => {
               this.editor.use(
                 new MarkdownExtension({
                   instance: this.editor,
-                  projectPath: this.currentProjectId,
+                  previewMarkdownPath: this.previewMarkdownPath,
                 }),
               );
             })
diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js
index e8c726d618424b4a3a741a49a1cddbb6451bad6c..bdffed7088298579c7c07d83cfece24747fb4850 100644
--- a/app/assets/javascripts/ide/index.js
+++ b/app/assets/javascripts/ide/index.js
@@ -63,6 +63,7 @@ export function initIde(el, options = {}) {
         editorTheme: window.gon?.user_color_scheme || DEFAULT_THEME,
         codesandboxBundlerUrl: el.dataset.codesandboxBundlerUrl,
         environmentsGuidanceAlertDismissed: !parseBoolean(el.dataset.enableEnvironmentsGuidance),
+        previewMarkdownPath: el.dataset.previewMarkdownPath,
       });
     },
     beforeDestroy() {
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index 83551e87f099322b5e7c5d5adc874a449ea88741..526987c750a565a30430bf3708136521ccbcce9f 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -32,4 +32,5 @@ export default () => ({
   codesandboxBundlerUrl: null,
   environmentsGuidanceAlertDismissed: false,
   environmentsGuidanceAlertDetected: false,
+  previewMarkdownPath: '',
 });
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index eccd0e7a34cabcab3322e757a339549aef73accb..c1a33794b509fc4497188162c30883112be7678d 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -220,7 +220,8 @@ def blob_editor_paths(project)
       'assets-prefix' => Gitlab::Application.config.assets.prefix,
       'blob-filename' => @blob && @blob.path,
       'project-id' => project.id,
-      'is-markdown' => @blob && @blob.path && Gitlab::MarkupHelper.gitlab_markdown?(@blob.path)
+      'is-markdown' => @blob && @blob.path && Gitlab::MarkupHelper.gitlab_markdown?(@blob.path),
+      'preview-markdown-path' => preview_markdown_path(project)
     }
   end
 
diff --git a/app/helpers/ide_helper.rb b/app/helpers/ide_helper.rb
index 41c7abbbabdf33cf1128b15aaad1202fb9771c2e..09ff57e2bafddf2937fc4a4024459645f2c1bc2b 100644
--- a/app/helpers/ide_helper.rb
+++ b/app/helpers/ide_helper.rb
@@ -19,7 +19,8 @@ def ide_data
       'merge-request' => @merge_request,
       'fork-info' => @fork_info&.to_json,
       'project' => convert_to_project_entity_json(@project),
-      'enable-environments-guidance' => enable_environments_guidance?.to_s
+      'enable-environments-guidance' => enable_environments_guidance?.to_s,
+      'preview-markdown-path' => @project && preview_markdown_path(@project)
     }
   end
 
diff --git a/spec/frontend/blob_edit/edit_blob_spec.js b/spec/frontend/blob_edit/edit_blob_spec.js
index 2be72ded0a2769178e0dca406fda57fa21b54ea8..ebef065675007c7675880b220203baf644b157c8 100644
--- a/spec/frontend/blob_edit/edit_blob_spec.js
+++ b/spec/frontend/blob_edit/edit_blob_spec.js
@@ -8,6 +8,8 @@ jest.mock('~/editor/source_editor');
 jest.mock('~/editor/extensions/source_editor_markdown_ext');
 jest.mock('~/editor/extensions/source_editor_file_template_ext');
 
+const PREVIEW_MARKDOWN_PATH = '/foo/bar/preview_markdown';
+
 describe('Blob Editing', () => {
   const useMock = jest.fn();
   const mockInstance = {
@@ -34,6 +36,7 @@ describe('Blob Editing', () => {
   const editorInst = (isMarkdown) => {
     return new EditBlob({
       isMarkdown,
+      previewMarkdownPath: PREVIEW_MARKDOWN_PATH,
     });
   };
 
@@ -44,6 +47,7 @@ describe('Blob Editing', () => {
 
   it('loads FileTemplateExtension by default', async () => {
     await initEditor();
+    expect(useMock).toHaveBeenCalledWith(expect.any(FileTemplateExtension));
     expect(FileTemplateExtension).toHaveBeenCalledTimes(1);
   });
 
@@ -55,9 +59,12 @@ describe('Blob Editing', () => {
 
     it('loads MarkdownExtension only for the markdown files', async () => {
       await initEditor(true);
-      expect(useMock).toHaveBeenCalledTimes(2);
-      expect(FileTemplateExtension).toHaveBeenCalledTimes(1);
+      expect(useMock).toHaveBeenCalledWith(expect.any(EditorMarkdownExtension));
       expect(EditorMarkdownExtension).toHaveBeenCalledTimes(1);
+      expect(EditorMarkdownExtension).toHaveBeenCalledWith({
+        instance: mockInstance,
+        previewMarkdownPath: PREVIEW_MARKDOWN_PATH,
+      });
     });
   });
 
diff --git a/spec/frontend/editor/source_editor_markdown_ext_spec.js b/spec/frontend/editor/source_editor_markdown_ext_spec.js
index 48ccc10e4868a47478b1abac73b2bd5b550df58e..245c6c28d3149023bc19a38476d836dcb2fd1c53 100644
--- a/spec/frontend/editor/source_editor_markdown_ext_spec.js
+++ b/spec/frontend/editor/source_editor_markdown_ext_spec.js
@@ -23,7 +23,7 @@ describe('Markdown Extension for Source Editor', () => {
   let editorEl;
   let panelSpy;
   let mockAxios;
-  const projectPath = 'fooGroup/barProj';
+  const previewMarkdownPath = '/gitlab/fooGroup/barProj/preview_markdown';
   const firstLine = 'This is a';
   const secondLine = 'multiline';
   const thirdLine = 'string with some **markup**';
@@ -57,7 +57,7 @@ describe('Markdown Extension for Source Editor', () => {
       blobPath: markdownPath,
       blobContent: text,
     });
-    editor.use(new EditorMarkdownExtension({ instance, projectPath }));
+    editor.use(new EditorMarkdownExtension({ instance, previewMarkdownPath }));
     panelSpy = jest.spyOn(EditorMarkdownExtension, 'togglePreviewPanel');
   });
 
@@ -74,7 +74,7 @@ describe('Markdown Extension for Source Editor', () => {
       shown: false,
       modelChangeListener: undefined,
     });
-    expect(instance.projectPath).toBe(projectPath);
+    expect(instance.previewMarkdownPath).toBe(previewMarkdownPath);
   });
 
   describe('model language changes listener', () => {
@@ -223,34 +223,24 @@ describe('Markdown Extension for Source Editor', () => {
   });
 
   describe('fetchPreview', () => {
-    const group = 'foo';
-    const project = 'bar';
-    const setData = (path, g, p) => {
-      instance.projectPath = path;
-      document.body.setAttribute('data-group', g);
-      document.body.setAttribute('data-project', p);
-    };
     const fetchPreview = async () => {
       instance.fetchPreview();
       await waitForPromises();
     };
 
+    let previewMarkdownSpy;
+
     beforeEach(() => {
-      mockAxios.onPost().reply(200, { body: responseData });
+      previewMarkdownSpy = jest.fn().mockImplementation(() => [200, { body: responseData }]);
+      mockAxios.onPost(previewMarkdownPath).replyOnce((req) => previewMarkdownSpy(req));
     });
 
-    it('correctly fetches preview based on projectPath', async () => {
-      setData(projectPath, group, project);
+    it('correctly fetches preview based on previewMarkdownPath', async () => {
       await fetchPreview();
-      expect(mockAxios.history.post[0].url).toBe(`/${projectPath}/preview_markdown`);
-      expect(mockAxios.history.post[0].data).toEqual(JSON.stringify({ text }));
-    });
 
-    it('correctly fetches preview based on group and project data attributes', async () => {
-      setData(undefined, group, project);
-      await fetchPreview();
-      expect(mockAxios.history.post[0].url).toBe(`/${group}/${project}/preview_markdown`);
-      expect(mockAxios.history.post[0].data).toEqual(JSON.stringify({ text }));
+      expect(previewMarkdownSpy).toHaveBeenCalledWith(
+        expect.objectContaining({ data: JSON.stringify({ text }) }),
+      );
     });
 
     it('puts the fetched content into the preview DOM element', async () => {
diff --git a/spec/frontend/ide/components/repo_editor_spec.js b/spec/frontend/ide/components/repo_editor_spec.js
index b2254de706c13f57ab28fc155ea7d0304ac20a90..47bcfb59a5f7f28060f6d35224afed37f362da6c 100644
--- a/spec/frontend/ide/components/repo_editor_spec.js
+++ b/spec/frontend/ide/components/repo_editor_spec.js
@@ -24,6 +24,8 @@ import axios from '~/lib/utils/axios_utils';
 import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue';
 import { file } from '../helpers';
 
+const PREVIEW_MARKDOWN_PATH = '/foo/bar/preview_markdown';
+
 const defaultFileProps = {
   ...file('file.txt'),
   content: 'hello world',
@@ -77,6 +79,7 @@ const prepareStore = (state, activeFile) => {
     entries: {
       [activeFile.path]: activeFile,
     },
+    previewMarkdownPath: PREVIEW_MARKDOWN_PATH,
   };
   const storeOptions = createStoreOptions();
   return new Vuex.Store({
@@ -278,10 +281,10 @@ describe('RepoEditor', () => {
       async ({ activeFile, viewer, shouldHaveMarkdownExtension } = {}) => {
         await createComponent({ state: { viewer }, activeFile });
         if (shouldHaveMarkdownExtension) {
-          expect(vm.editor.projectPath).toBe(vm.currentProjectId);
+          expect(vm.editor.previewMarkdownPath).toBe(PREVIEW_MARKDOWN_PATH);
           expect(vm.editor.togglePreview).toBeDefined();
         } else {
-          expect(vm.editor.projectPath).toBeUndefined();
+          expect(vm.editor.previewMarkdownPath).toBeUndefined();
           expect(vm.editor.togglePreview).toBeUndefined();
         }
       },
diff --git a/spec/helpers/ide_helper_spec.rb b/spec/helpers/ide_helper_spec.rb
index d34358e49c0b3d985d4a6b560bf5fa0b3df9b819..503ad3ad66d69a0d331f9903427a4580f61702c5 100644
--- a/spec/helpers/ide_helper_spec.rb
+++ b/spec/helpers/ide_helper_spec.rb
@@ -18,7 +18,8 @@
             'file-path' => nil,
             'merge-request' => nil,
             'fork-info' => nil,
-            'project' => nil
+            'project' => nil,
+            'preview-markdown-path' => nil
           )
       end
     end
@@ -41,7 +42,8 @@
             'file-path' => 'foo/bar',
             'merge-request' => '1',
             'fork-info' => fork_info.to_json,
-            'project' => serialized_project
+            'project' => serialized_project,
+            'preview-markdown-path' => Gitlab::Routing.url_helpers.preview_markdown_project_path(project)
           )
       end
     end