diff --git a/lib/config/presets.js b/lib/config/presets.js
index 8635ff19b8f6a81d29feb0c6e99e3352e081ecba..fa3a747e7f92d14f655d8a6e7eb04fc6a9ad4bb9 100644
--- a/lib/config/presets.js
+++ b/lib/config/presets.js
@@ -2,8 +2,14 @@ const is = require('@sindresorhus/is');
 const configParser = require('./index');
 const massage = require('./massage');
 const migration = require('./migration');
+const github = require('../datasource/github');
 const npm = require('../datasource/npm');
 
+const datasources = {
+  github,
+  npm,
+};
+
 module.exports = {
   resolveConfigPresets,
   replaceArgs,
@@ -117,9 +123,16 @@ function replaceArgs(obj, argMapping) {
 
 function parsePreset(input) {
   let str = input;
+  let datasource;
   let packageName;
   let presetName;
   let params;
+  if (str.startsWith('github>')) {
+    datasource = 'github';
+    str = str.substring('github>'.length);
+  }
+  str = str.replace(/^npm>/, '');
+  datasource = datasource || 'npm';
   if (str.includes('(')) {
     params = str
       .slice(str.indexOf('(') + 1, -1)
@@ -147,20 +160,23 @@ function parsePreset(input) {
     // non-scoped namespace
     [, packageName] = str.match(/(.*?)(:|$)/);
     presetName = str.slice(packageName.length + 1);
-    if (!packageName.startsWith('renovate-config-')) {
+    if (datasource === 'npm' && !packageName.startsWith('renovate-config-')) {
       packageName = `renovate-config-${packageName}`;
     }
     if (presetName === '') {
       presetName = 'default';
     }
   }
-  return { packageName, presetName, params };
+  return { datasource, packageName, presetName, params };
 }
 
 async function getPreset(preset) {
   logger.trace(`getPreset(${preset})`);
-  const { packageName, presetName, params } = parsePreset(preset);
-  let presetConfig = await npm.getPreset(packageName, presetName);
+  const { datasource, packageName, presetName, params } = parsePreset(preset);
+  let presetConfig = await datasources[datasource].getPreset(
+    packageName,
+    presetName
+  );
   logger.trace({ presetConfig }, `Found preset ${preset}`);
   if (params) {
     const argMapping = {};
diff --git a/lib/datasource/github.js b/lib/datasource/github.js
index 30563b1d413afd81f82b8b2460face27d3fb5791..3949cca124cdb4a1ee8bd8c43277479d1938f9bb 100644
--- a/lib/datasource/github.js
+++ b/lib/datasource/github.js
@@ -2,9 +2,33 @@ const ghGot = require('../platform/github/gh-got-wrapper');
 const versioning = require('../versioning');
 
 module.exports = {
+  getPreset,
   getPkgReleases,
 };
 
+async function getPreset(pkgName, presetName = 'default') {
+  if (presetName !== 'default') {
+    throw new Error(
+      { pkgName, presetName },
+      'Sub-preset names are not supported with GitHub datasource'
+    );
+  }
+  let res;
+  try {
+    const url = `repos/${pkgName}/contents/renovate.json`;
+    res = Buffer.from((await ghGot(url)).body.content, 'base64').toString();
+  } catch (err) {
+    logger.debug('Failed to retrieve renovate.json from repo');
+    throw new Error('dep not found');
+  }
+  try {
+    return JSON.parse(res);
+  } catch (err) {
+    logger.debug('Failed to parse renovate.json');
+    throw new Error('invalid preset JSON');
+  }
+}
+
 async function getPkgReleases(purl, config) {
   const { versionScheme } = config || {};
   const { fullname: repo, qualifiers: options } = purl;
diff --git a/test/config/__snapshots__/presets.spec.js.snap b/test/config/__snapshots__/presets.spec.js.snap
index 2d174c2e52bef8f0d730a5d4f644aad768c60160..6e278403f1597df8fcf523aefde6dd8dd165e5f1 100644
--- a/test/config/__snapshots__/presets.spec.js.snap
+++ b/test/config/__snapshots__/presets.spec.js.snap
@@ -80,8 +80,18 @@ Object {
 }
 `;
 
+exports[`config/presets parsePreset parses github 1`] = `
+Object {
+  "datasource": "github",
+  "packageName": "some/repo",
+  "params": undefined,
+  "presetName": "default",
+}
+`;
+
 exports[`config/presets parsePreset returns default package name 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "renovate-config-default",
   "params": undefined,
   "presetName": "base",
@@ -90,6 +100,7 @@ Object {
 
 exports[`config/presets parsePreset returns default package name with params 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "renovate-config-default",
   "params": Array [
     "packages/eslint",
@@ -101,6 +112,7 @@ Object {
 
 exports[`config/presets parsePreset returns non-scoped default 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "renovate-config-somepackage",
   "params": undefined,
   "presetName": "default",
@@ -109,6 +121,7 @@ Object {
 
 exports[`config/presets parsePreset returns non-scoped package name 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "renovate-config-somepackage",
   "params": undefined,
   "presetName": "webapp",
@@ -117,6 +130,7 @@ Object {
 
 exports[`config/presets parsePreset returns non-scoped package name full 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "renovate-config-somepackage",
   "params": undefined,
   "presetName": "webapp",
@@ -125,6 +139,7 @@ Object {
 
 exports[`config/presets parsePreset returns non-scoped package name with params 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "renovate-config-somepackage",
   "params": Array [
     "param1",
@@ -135,6 +150,7 @@ Object {
 
 exports[`config/presets parsePreset returns scope with packageName and default 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "@somescope/somepackagename",
   "params": undefined,
   "presetName": "default",
@@ -143,6 +159,7 @@ Object {
 
 exports[`config/presets parsePreset returns scope with packageName and params and default 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "@somescope/somepackagename",
   "params": Array [
     "param1",
@@ -155,6 +172,7 @@ Object {
 
 exports[`config/presets parsePreset returns scope with packageName and presetName 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "@somescope/somepackagename",
   "params": undefined,
   "presetName": "somePresetName",
@@ -163,6 +181,7 @@ Object {
 
 exports[`config/presets parsePreset returns scope with packageName and presetName and params 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "@somescope/somepackagename",
   "params": Array [
     "param1",
@@ -174,6 +193,7 @@ Object {
 
 exports[`config/presets parsePreset returns scope with presetName 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "@somescope/renovate-config",
   "params": undefined,
   "presetName": "somePresetName",
@@ -182,6 +202,7 @@ Object {
 
 exports[`config/presets parsePreset returns scope with presetName and params 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "@somescope/renovate-config",
   "params": Array [
     "param1",
@@ -192,6 +213,7 @@ Object {
 
 exports[`config/presets parsePreset returns simple scope 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "@somescope/renovate-config",
   "params": undefined,
   "presetName": "default",
@@ -200,6 +222,7 @@ Object {
 
 exports[`config/presets parsePreset returns simple scope and params 1`] = `
 Object {
+  "datasource": "npm",
   "packageName": "@somescope/renovate-config",
   "params": Array [
     "param1",
diff --git a/test/config/presets.spec.js b/test/config/presets.spec.js
index 44b056bac87f5fd548ecfe7a3de1b55966ea473a..7bb69d34ef5b92db2b4f657b3a73de6608597a5e 100644
--- a/test/config/presets.spec.js
+++ b/test/config/presets.spec.js
@@ -207,6 +207,9 @@ describe('config/presets', () => {
     it('returns default package name', () => {
       expect(presets.parsePreset(':base')).toMatchSnapshot();
     });
+    it('parses github', () => {
+      expect(presets.parsePreset('github>some/repo')).toMatchSnapshot();
+    });
     it('returns default package name with params', () => {
       expect(
         presets.parsePreset(':group(packages/eslint, eslint)')
diff --git a/test/datasource/github.spec.js b/test/datasource/github.spec.js
index 82e57a4f6175877373bc4163a5d2b5e6c28ede65..86d35bfc6a829eb865d5fbd6ec1c5fc6ee09dc11 100644
--- a/test/datasource/github.spec.js
+++ b/test/datasource/github.spec.js
@@ -1,10 +1,41 @@
 const datasource = require('../../lib/datasource');
+const github = require('../../lib/datasource/github');
 const ghGot = require('../../lib/platform/github/gh-got-wrapper');
 
 jest.mock('../../lib/platform/github/gh-got-wrapper');
 jest.mock('got');
 
 describe('datasource/github', () => {
+  describe('getPreset()', () => {
+    it('throws if non-default', async () => {
+      await expect(
+        github.getPreset('some/repo', 'non-default')
+      ).rejects.toThrow();
+    });
+    it('throws if no content', async () => {
+      ghGot.mockImplementationOnce(() => ({
+        body: {},
+      }));
+      await expect(github.getPreset('some/repo')).rejects.toThrow();
+    });
+    it('throws if fails to parse', async () => {
+      ghGot.mockImplementationOnce(() => ({
+        body: {
+          content: Buffer.from('not json').toString('base64'),
+        },
+      }));
+      await expect(github.getPreset('some/repo')).rejects.toThrow();
+    });
+    it('should return the preset', async () => {
+      ghGot.mockImplementationOnce(() => ({
+        body: {
+          content: Buffer.from('{"foo":"bar"}').toString('base64'),
+        },
+      }));
+      const content = await github.getPreset('some/repo');
+      expect(content).toEqual({ foo: 'bar' });
+    });
+  });
   describe('getPkgReleases', () => {
     it('returns cleaned tags', async () => {
       const body = [