diff --git a/lib/api/github.js b/lib/api/github.js
index 13e727057fd8909c70ebc0d1d22a0474b709bc60..3a7d4a3eb267d8d9e5209f9fc77315d0de491cbf 100644
--- a/lib/api/github.js
+++ b/lib/api/github.js
@@ -147,6 +147,7 @@ async function initRepo(repoName, token, endpoint, repoLogger) {
     process.env.GITHUB_ENDPOINT = endpoint;
   }
   config.repoName = repoName;
+  config.fileList = null;
   const platformConfig = {};
   try {
     const res = await ghGotRetry(`repos/${repoName}`, {
@@ -226,29 +227,32 @@ async function setBaseBranch(branchName) {
 
 // Search
 
-// Returns an array of file paths in current repo matching the fileName
-async function findFilePaths(fileName, content) {
-  let results = [];
-  let url = `search/code?q=`;
-  if (content) {
-    url += `${content}+`;
+// Get full file list
+async function getFileList(branchName) {
+  if (config.fileList) {
+    return config.fileList;
   }
-  url += `repo:${config.repoName}+filename:${fileName}&per_page=100`;
-  do {
-    const res = await ghGotRetry(url);
-    const exactMatches = res.body.items.filter(item => item.name === fileName);
-    // GitHub seems to return files in the root with a leading `/`
-    // which then breaks things later on down the line
-    results = results.concat(
-      exactMatches.map(item => item.path.replace(/^\//, ''))
-    );
-    const linkHeader = res.headers.link || '';
-    const matches = linkHeader.match(
-      /<https:\/\/api.github\.com\/(.*?)>; rel="next".*/
+  const res = await ghGotRetry(
+    `repos/${config.repoName}/git/trees/${branchName}?recursive=true`
+  );
+  if (res.body.truncated) {
+    logger.warn(
+      { repository: config.repoName },
+      'repository tree is truncated'
     );
-    url = matches ? matches[1] : null;
-  } while (url);
-  return results;
+  }
+  config.fileList = res.body.tree
+    .filter(item => item.type === 'blob')
+    .map(item => item.path)
+    .sort();
+  return config.fileList;
+}
+
+// Return all files in the repository matching the filename
+async function findFilePaths(fileName, branchName = config.baseBranch) {
+  return (await getFileList(branchName)).filter(fullFilePath =>
+    fullFilePath.endsWith(fileName)
+  );
 }
 
 // Branch
diff --git a/lib/api/gitlab.js b/lib/api/gitlab.js
index 443aa3c64c7fe2f5607b79e933e9bec9bef33669..48d3f6a0eab46af0f15755aa2bc309fdf5520417 100644
--- a/lib/api/gitlab.js
+++ b/lib/api/gitlab.js
@@ -101,6 +101,7 @@ async function initRepo(repoName, token, endpoint, repoLogger) {
   }
   logger.debug(`Detected Gitlab API ${config.apiVersion}`);
   config.repoName = repoName.replace('/', '%2F');
+  config.fileList = null;
   try {
     const res = await glGot(`projects/${config.repoName}`);
     config.defaultBranch = res.body.default_branch;
@@ -123,10 +124,26 @@ async function setBaseBranch(branchName) {
 
 // Search
 
-// Returns an array of file paths in current repo matching the fileName
-async function findFilePaths() {
-  logger.debug("Can't find multiple package.json files in GitLab");
-  return [];
+// Get full file list
+async function getFileList(branchName) {
+  if (config.fileList) {
+    return config.fileList;
+  }
+  const res = await glGot(
+    `projects/${config.repoName}/repository/tree?ref=${branchName}&recursive=1`
+  );
+  config.fileList = res.body
+    .filter(item => item.type === 'blob')
+    .map(item => item.path)
+    .sort();
+  return config.fileList;
+}
+
+// Return all files in the repository matching the filename
+async function findFilePaths(fileName, branchName = config.baseBranch) {
+  return (await getFileList(branchName)).filter(fullFilePath =>
+    fullFilePath.endsWith(fileName)
+  );
 }
 
 // Branch
diff --git a/lib/workers/repository/apis.js b/lib/workers/repository/apis.js
index d035572fe750ad259aaa4946a19c0c720636cfc1..a95d5e7f119bcb656d6f314fb44cb731029b2ef4 100644
--- a/lib/workers/repository/apis.js
+++ b/lib/workers/repository/apis.js
@@ -280,22 +280,13 @@ async function detectPackageFiles(input, detectAllLanguages = false) {
         );
       }
     }
-    if (config.packageFiles.length === 0) {
-      logger.debug('Checking manually if repository has a package.json');
-      if (await config.api.getFileJson('package.json')) {
-        config.packageFiles = ['package.json'];
-      }
-    }
     if (config.packageFiles.length) {
       config.types.npm = true;
     }
   }
   if (detectAllLanguages || config.meteor.enabled) {
     logger.debug('Detecting meteor package.js files');
-    const meteorPackageFiles = await config.api.findFilePaths(
-      'package.js',
-      'Npm.depends'
-    );
+    const meteorPackageFiles = await config.api.findFilePaths('package.js');
     if (meteorPackageFiles.length) {
       logger.info(
         { count: meteorPackageFiles.length },
diff --git a/test/api/__snapshots__/github.spec.js.snap b/test/api/__snapshots__/github.spec.js.snap
index 0cc62aac05d7ecceb4ec875a02262a1481bed5b2..d3bc2955f24525d86feff34a3894e6da302e8455 100644
--- a/test/api/__snapshots__/github.spec.js.snap
+++ b/test/api/__snapshots__/github.spec.js.snap
@@ -452,106 +452,7 @@ Array [
 ]
 `;
 
-exports[`api/github findFilePaths(fileName) paginates 1`] = `
-Array [
-  Array [
-    "repos/some/repo",
-    Object {
-      "headers": Object {
-        "accept": "application/vnd.github.loki-preview+json",
-      },
-    },
-  ],
-  Array [
-    "repos/some/repo/git/refs/heads/master",
-    undefined,
-  ],
-  Array [
-    "repos/some/repo/branches/master/protection/required_status_checks",
-    Object {
-      "headers": Object {
-        "accept": "application/vnd.github.loki-preview+json",
-      },
-    },
-  ],
-  Array [
-    "search/code?q=repo:some/repo+filename:package.json&per_page=100",
-    undefined,
-  ],
-  Array [
-    "search/code?q=repo%3Arenovate-tests%2Fonboarding-1+filename%3Apackage.json&per_page=2&page=2",
-    undefined,
-  ],
-]
-`;
-
-exports[`api/github findFilePaths(fileName) paginates 2`] = `
-Array [
-  "package.json",
-  "src/app/package.json",
-  "src/otherapp/package.json",
-]
-`;
-
-exports[`api/github findFilePaths(fileName) should return empty array if none found 1`] = `
-Array [
-  Array [
-    "repos/some/repo",
-    Object {
-      "headers": Object {
-        "accept": "application/vnd.github.loki-preview+json",
-      },
-    },
-  ],
-  Array [
-    "repos/some/repo/git/refs/heads/master",
-    undefined,
-  ],
-  Array [
-    "repos/some/repo/branches/master/protection/required_status_checks",
-    Object {
-      "headers": Object {
-        "accept": "application/vnd.github.loki-preview+json",
-      },
-    },
-  ],
-  Array [
-    "search/code?q=repo:some/repo+filename:package.json&per_page=100",
-    undefined,
-  ],
-]
-`;
-
 exports[`api/github findFilePaths(fileName) should return the files matching the fileName 1`] = `
-Array [
-  Array [
-    "repos/some/repo",
-    Object {
-      "headers": Object {
-        "accept": "application/vnd.github.loki-preview+json",
-      },
-    },
-  ],
-  Array [
-    "repos/some/repo/git/refs/heads/master",
-    undefined,
-  ],
-  Array [
-    "repos/some/repo/branches/master/protection/required_status_checks",
-    Object {
-      "headers": Object {
-        "accept": "application/vnd.github.loki-preview+json",
-      },
-    },
-  ],
-  Array [
-    "search/code?q=some-content+repo:some/repo+filename:package.json&per_page=100",
-    undefined,
-  ],
-]
-`;
-
-exports[`api/github findFilePaths(fileName) should return the files matching the fileName 2`] = `
 Array [
   "package.json",
   "src/app/package.json",
diff --git a/test/api/__snapshots__/gitlab.spec.js.snap b/test/api/__snapshots__/gitlab.spec.js.snap
index a3f769b1fcb0794e51688ce15ad93e8ad0f1ba9b..4b1036017a31553ee16ec58f873b6f5e82b1d7be 100644
--- a/test/api/__snapshots__/gitlab.spec.js.snap
+++ b/test/api/__snapshots__/gitlab.spec.js.snap
@@ -193,6 +193,14 @@ Array [
 ]
 `;
 
+exports[`api/gitlab findFilePaths(fileName) should return the files matching the fileName 1`] = `
+Array [
+  "package.json",
+  "src/app/package.json",
+  "src/otherapp/package.json",
+]
+`;
+
 exports[`api/gitlab getBranch returns a branch 1`] = `"foo"`;
 
 exports[`api/gitlab getBranchLastCommitTime should return a Date 1`] = `2012-09-20T08:50:22.000Z`;
diff --git a/test/api/github.spec.js b/test/api/github.spec.js
index bc110a81a5036e05e95a6cc34f95b1dc5f3d163d..9d6e245dc6aa31e072af95a8a928c1b418b76aa3 100644
--- a/test/api/github.spec.js
+++ b/test/api/github.spec.js
@@ -594,66 +594,46 @@ describe('api/github', () => {
     });
   });
   describe('findFilePaths(fileName)', () => {
-    it('should return empty array if none found', async () => {
+    it('warns if truncated result', async () => {
       await initRepo('some/repo', 'token');
       ghGot.mockImplementationOnce(() => ({
-        headers: { link: '' },
         body: {
-          items: [],
+          truncated: true,
+          tree: [],
         },
       }));
       const files = await github.findFilePaths('package.json');
-      expect(ghGot.mock.calls).toMatchSnapshot();
       expect(files.length).toBe(0);
     });
-    it('should return the files matching the fileName', async () => {
+    it('caches the result', async () => {
       await initRepo('some/repo', 'token');
       ghGot.mockImplementationOnce(() => ({
-        headers: { link: '' },
         body: {
-          items: [
-            { name: 'package.json', path: '/package.json' },
-            {
-              name: 'package.json.something-else',
-              path: 'some-dir/package.json.some-thing-else',
-            },
-            { name: 'package.json', path: 'src/app/package.json' },
-            { name: 'package.json', path: 'src/otherapp/package.json' },
-          ],
+          truncated: true,
+          tree: [],
         },
       }));
-      const files = await github.findFilePaths('package.json', 'some-content');
-      expect(ghGot.mock.calls).toMatchSnapshot();
-      expect(files).toMatchSnapshot();
+      let files = await github.findFilePaths('package.json');
+      expect(files.length).toBe(0);
+      files = await github.findFilePaths('package.js');
+      expect(files.length).toBe(0);
     });
-    it('paginates', async () => {
+    it('should return the files matching the fileName', async () => {
       await initRepo('some/repo', 'token');
       ghGot.mockImplementationOnce(() => ({
-        headers: {
-          link:
-            '<https://api.github.com/search/code?q=repo%3Arenovate-tests%2Fonboarding-1+filename%3Apackage.json&per_page=2&page=2>; rel="next", <https://api.github.com/search/code?q=repo%3Arenovate-tests%2Fonboarding-1+filename%3Apackage.json&per_page=2&page=2>; rel="last" <https://api.github.com/search/code?q=repo%3Arenovate-tests%2Fonboarding-1+filename%3Apackage.json&per_page=2&page=1>; rel="first", <https://api.github.com/search/code?q=repo%3Arenovate-tests%2Fonboarding-1+filename%3Apackage.json&per_page=2&page=1>; rel="prev"',
-        },
         body: {
-          items: [
-            { name: 'package.json', path: '/package.json' },
+          tree: [
+            { type: 'blob', path: 'package.json' },
             {
-              name: 'package.json.something-else',
+              type: 'blob',
               path: 'some-dir/package.json.some-thing-else',
             },
-          ],
-        },
-      }));
-      ghGot.mockImplementationOnce(() => ({
-        headers: { link: '' },
-        body: {
-          items: [
-            { name: 'package.json', path: 'src/app/package.json' },
-            { name: 'package.json', path: 'src/otherapp/package.json' },
+            { type: 'blob', path: 'src/app/package.json' },
+            { type: 'blob', path: 'src/otherapp/package.json' },
           ],
         },
       }));
       const files = await github.findFilePaths('package.json');
-      expect(ghGot.mock.calls).toMatchSnapshot();
       expect(files).toMatchSnapshot();
     });
   });
diff --git a/test/api/gitlab.spec.js b/test/api/gitlab.spec.js
index 1780f09412a951e8f5d26ac6bd1be59f5ef00416..aaa65a26dff7fcbf2a2503d75bcc7d846e475d84 100644
--- a/test/api/gitlab.spec.js
+++ b/test/api/gitlab.spec.js
@@ -191,11 +191,40 @@ describe('api/gitlab', () => {
     });
   });
   describe('findFilePaths(fileName)', () => {
-    it('should return empty array', async () => {
+    it('warns if truncated result', async () => {
       await initRepo('some/repo', 'token');
+      glGot.mockImplementationOnce(() => ({
+        body: [],
+      }));
       const files = await gitlab.findFilePaths('package.json');
       expect(files.length).toBe(0);
     });
+    it('caches the result', async () => {
+      await initRepo('some/repo', 'token');
+      glGot.mockImplementationOnce(() => ({
+        body: [],
+      }));
+      let files = await gitlab.findFilePaths('package.json');
+      expect(files.length).toBe(0);
+      files = await gitlab.findFilePaths('package.js');
+      expect(files.length).toBe(0);
+    });
+    it('should return the files matching the fileName', async () => {
+      await initRepo('some/repo', 'token');
+      glGot.mockImplementationOnce(() => ({
+        body: [
+          { type: 'blob', path: 'package.json' },
+          {
+            type: 'blob',
+            path: 'some-dir/package.json.some-thing-else',
+          },
+          { type: 'blob', path: 'src/app/package.json' },
+          { type: 'blob', path: 'src/otherapp/package.json' },
+        ],
+      }));
+      const files = await gitlab.findFilePaths('package.json');
+      expect(files).toMatchSnapshot();
+    });
   });
   describe('branchExists(branchName)', () => {
     it('should return true if 200 OK', async () => {
diff --git a/test/workers/repository/__snapshots__/apis.spec.js.snap b/test/workers/repository/__snapshots__/apis.spec.js.snap
index 3e22cd325917f38026889b1247d209937a387058..a927fdfe7a1cd8a6fb775e118ea3cb5ddb09a309 100644
--- a/test/workers/repository/__snapshots__/apis.spec.js.snap
+++ b/test/workers/repository/__snapshots__/apis.spec.js.snap
@@ -37,12 +37,6 @@ Array [
 ]
 `;
 
-exports[`workers/repository/apis detectPackageFiles(config) defaults to package.json if found 1`] = `
-Array [
-  "package.json",
-]
-`;
-
 exports[`workers/repository/apis detectPackageFiles(config) finds Dockerfiles 1`] = `
 Array [
   "package.json",
diff --git a/test/workers/repository/apis.spec.js b/test/workers/repository/apis.spec.js
index b6b2173b9016d58af1ce1b2dcf44413f4a393c34..3db5589fdef2ec93f3746d7fe51402baccd99f34 100644
--- a/test/workers/repository/apis.spec.js
+++ b/test/workers/repository/apis.spec.js
@@ -320,31 +320,6 @@ describe('workers/repository/apis', () => {
       expect(res.foundIgnoredPaths).toMatchSnapshot();
       expect(res.warnings).toMatchSnapshot();
     });
-    it('defaults to package.json if found', async () => {
-      const config = {
-        ...defaultConfig,
-        api: {
-          findFilePaths: jest.fn(() => []),
-          getFileJson: jest.fn(() => ({})),
-        },
-        logger,
-      };
-      const res = await apis.detectPackageFiles(config);
-      expect(res.packageFiles).toHaveLength(1);
-      expect(res.packageFiles).toMatchSnapshot();
-    });
-    it('returns empty if package.json not found', async () => {
-      const config = {
-        ...defaultConfig,
-        api: {
-          findFilePaths: jest.fn(() => []),
-          getFileJson: jest.fn(() => null),
-        },
-        logger,
-      };
-      const res = await apis.detectPackageFiles(config);
-      expect(res.packageFiles).toEqual([]);
-    });
   });
   describe('resolvePackageFiles', () => {
     let config;
diff --git a/test/workers/repository/onboarding.spec.js b/test/workers/repository/onboarding.spec.js
index 8132c0151061c316ea795f90053eea7282e60d36..2c5baebccaaa1497d1618954e26db46e96b0e3ba 100644
--- a/test/workers/repository/onboarding.spec.js
+++ b/test/workers/repository/onboarding.spec.js
@@ -267,6 +267,8 @@ describe('lib/workers/repository/onboarding', () => {
       expect(config.api.commitFilesToBranch.mock.calls.length).toBe(0);
     });
     it('commits files and returns false if no pr', async () => {
+      config.api.findFilePaths.mockReturnValueOnce(['package.json']);
+      config.api.findFilePaths.mockReturnValue([]);
       const res = await onboarding.getOnboardingStatus(config);
       expect(res.repoIsOnboarded).toEqual(false);
       expect(config.api.findPr.mock.calls.length).toBe(1);
@@ -274,6 +276,8 @@ describe('lib/workers/repository/onboarding', () => {
       expect(config.api.commitFilesToBranch.mock.calls[0]).toMatchSnapshot();
     });
     it('pins private repos', async () => {
+      config.api.findFilePaths.mockReturnValueOnce(['package.json']);
+      config.api.findFilePaths.mockReturnValue([]);
       onboarding.isRepoPrivate.mockReturnValueOnce(true);
       const res = await onboarding.getOnboardingStatus(config);
       expect(res.repoIsOnboarded).toEqual(false);