diff --git a/app/assets/javascripts/blob/pdf/pdf_viewer.vue b/app/assets/javascripts/blob/pdf/pdf_viewer.vue
index 96d6f5009604d81d58518251dc12cd17857b2080..a1a62abeb6fca330d548f61ccac08c431f798e40 100644
--- a/app/assets/javascripts/blob/pdf/pdf_viewer.vue
+++ b/app/assets/javascripts/blob/pdf/pdf_viewer.vue
@@ -38,7 +38,13 @@ export default {
     <div v-if="loading && !error" class="text-center loading">
       <gl-loading-icon class="mt-5" size="lg" />
     </div>
-    <pdf-lab v-if="!loadError" :pdf="pdf" @pdflabload="onLoad" @pdflaberror="onError" />
+    <pdf-lab
+      v-if="!loadError"
+      :pdf="pdf"
+      @pdflabload="onLoad"
+      @pdflaberror="onError"
+      v-on="$listeners"
+    />
     <p v-if="error" class="text-center">
       <span v-if="loadError" ref="loadError">
         {{ __('An error occurred while loading the file. Please try again later.') }}
diff --git a/app/assets/javascripts/pdf/index.vue b/app/assets/javascripts/pdf/index.vue
index 6a64538abfea7cb8abff111d12a4f8037a95d283..644eccc023258825a5216d438df21e1b5acaa589 100644
--- a/app/assets/javascripts/pdf/index.vue
+++ b/app/assets/javascripts/pdf/index.vue
@@ -45,7 +45,7 @@ export default {
         .promise.then(this.renderPages)
         .then((pages) => {
           this.pages = pages;
-          this.$emit('pdflabload');
+          this.$emit('pdflabload', pages.length);
         })
         .catch((error) => {
           this.$emit('pdflaberror', error);
diff --git a/app/assets/javascripts/repository/components/blob_viewers/index.js b/app/assets/javascripts/repository/components/blob_viewers/index.js
index b5c4c81b9d87ae53445c05fecae16623b615f43c..62d687e848b16c11e98e0ce6592b09f761081897 100644
--- a/app/assets/javascripts/repository/components/blob_viewers/index.js
+++ b/app/assets/javascripts/repository/components/blob_viewers/index.js
@@ -40,6 +40,7 @@ export const viewerProps = (type, blob) => {
     },
     pdf: {
       url: blob.rawPath,
+      fileSize: blob.rawSize,
     },
   }[type];
 };
diff --git a/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue b/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue
index 3eefcd64b135185e48dd01613bfbd645ff88e70a..ff5d7891660e4853bf048b0d96a133df0b263dcb 100644
--- a/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue
+++ b/app/assets/javascripts/repository/components/blob_viewers/pdf_viewer.vue
@@ -1,16 +1,57 @@
 <script>
+import { GlButton } from '@gitlab/ui';
 import PdfViewer from '~/blob/pdf/pdf_viewer.vue';
+import { __ } from '~/locale';
+import { PDF_MAX_FILE_SIZE, PDF_MAX_PAGE_LIMIT } from '../../constants';
 
 export default {
-  components: { PdfViewer },
+  components: { GlButton, PdfViewer },
+  i18n: {
+    tooLargeDescription: __('This PDF is too large to display, please download to view.'),
+    tooLargeButtonText: __('Download PDF'),
+  },
   props: {
     url: {
       type: String,
       required: true,
     },
+    fileSize: {
+      type: Number,
+      required: true,
+    },
+  },
+  data() {
+    return { totalPages: 0 };
+  },
+  computed: {
+    tooLargeToDisplay() {
+      return this.fileSize > PDF_MAX_FILE_SIZE || this.totalPages > PDF_MAX_PAGE_LIMIT;
+    },
+  },
+  methods: {
+    handleOnLoad(totalPages) {
+      this.totalPages = totalPages;
+    },
   },
 };
 </script>
 <template>
-  <pdf-viewer :pdf="url" />
+  <div>
+    <pdf-viewer v-if="!tooLargeToDisplay" :pdf="url" @pdflabload="handleOnLoad" />
+
+    <div v-else class="gl-display-flex gl-flex-direction-column gl-align-items-center gl-p-5">
+      <p data-testid="download-help-text">{{ $options.i18n.tooLargeDescription }}</p>
+
+      <gl-button
+        icon="download"
+        category="secondary"
+        variant="confirm"
+        :href="url"
+        :aria-label="$options.i18n.tooLargeButtonText"
+        :title="$options.i18n.tooLargeButtonText"
+        download
+        >{{ $options.i18n.tooLargeButtonText }}</gl-button
+      >
+    </div>
+  </div>
 </template>
diff --git a/app/assets/javascripts/repository/constants.js b/app/assets/javascripts/repository/constants.js
index b4363c5116536dec1d9dad17ebb66131ef72eec0..cdc4818e4931f4680330ec9d6892a713b5951cc3 100644
--- a/app/assets/javascripts/repository/constants.js
+++ b/app/assets/javascripts/repository/constants.js
@@ -20,3 +20,6 @@ export const COMMIT_MESSAGE_BODY_MAX_LENGTH = 72;
 export const LIMITED_CONTAINER_WIDTH_CLASS = 'limit-container-width';
 
 export const I18N_COMMIT_DATA_FETCH_ERROR = __('An error occurred while fetching commit data.');
+
+export const PDF_MAX_FILE_SIZE = 10000000; // 10 MB
+export const PDF_MAX_PAGE_LIMIT = 50;
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 8ea49e00eac6c5aee6e254ac3c5f8e3718ec4ac2..5b53825626da6f1ef83ded5c683ce59903e960fa 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -12515,6 +12515,9 @@ msgstr ""
 msgid "Download CSV"
 msgstr ""
 
+msgid "Download PDF"
+msgstr ""
+
 msgid "Download artifacts"
 msgstr ""
 
@@ -35549,6 +35552,9 @@ msgstr ""
 msgid "This GitLab instance is undergoing maintenance and is operating in read-only mode."
 msgstr ""
 
+msgid "This PDF is too large to display, please download to view."
+msgstr ""
+
 msgid "This Project is currently archived and read-only. Please unarchive the project first if you want to resume Pull mirroring"
 msgstr ""
 
diff --git a/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js b/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js
index adee5b9086327c96f0d56c285de009329e1f5105..7d83b66e96d7eee93131aaebf13bbe0b364278b8 100644
--- a/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_viewers/pdf_viewer_spec.js
@@ -1,22 +1,63 @@
 import { shallowMount } from '@vue/test-utils';
+import { GlButton } from '@gitlab/ui';
 import Component from '~/repository/components/blob_viewers/pdf_viewer.vue';
 import PdfViewer from '~/blob/pdf/pdf_viewer.vue';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
 
 describe('PDF Viewer', () => {
   let wrapper;
 
-  const propsData = { url: 'some/pdf_blob.pdf' };
+  const defaultPropsData = { url: 'some/pdf_blob.pdf' };
 
-  const createComponent = () => {
-    wrapper = shallowMount(Component, { propsData });
+  const createComponent = (fileSize = 999) => {
+    wrapper = extendedWrapper(
+      shallowMount(Component, { propsData: { ...defaultPropsData, fileSize } }),
+    );
   };
 
   const findPDFViewer = () => wrapper.findComponent(PdfViewer);
+  const findHelpText = () => wrapper.findByTestId('download-help-text');
+  const findDownLoadButton = () => wrapper.findComponent(GlButton);
 
   it('renders a PDF Viewer component', () => {
     createComponent();
 
     expect(findPDFViewer().exists()).toBe(true);
-    expect(findPDFViewer().props('pdf')).toBe(propsData.url);
+    expect(findPDFViewer().props('pdf')).toBe(defaultPropsData.url);
+  });
+
+  describe('Too large', () => {
+    beforeEach(() => createComponent(20000000));
+
+    it('does not a PDF Viewer component', () => {
+      expect(findPDFViewer().exists()).toBe(false);
+    });
+
+    it('renders help text', () => {
+      expect(findHelpText().text()).toBe(
+        'This PDF is too large to display, please download to view.',
+      );
+    });
+
+    it('renders a download button', () => {
+      expect(findDownLoadButton().exists()).toBe(true);
+      expect(findDownLoadButton().text()).toBe('Download PDF');
+      expect(findDownLoadButton().props('icon')).toBe('download');
+    });
+  });
+
+  describe('Too many pages', () => {
+    beforeEach(() => {
+      createComponent();
+      findPDFViewer().vm.$emit('pdflabload', 100);
+    });
+
+    it('does not a PDF Viewer component', () => {
+      expect(findPDFViewer().exists()).toBe(false);
+    });
+
+    it('renders a download button', () => {
+      expect(findDownLoadButton().exists()).toBe(true);
+    });
   });
 });