diff --git a/lib/config/definitions.ts b/lib/config/definitions.ts
index 28742981dfb99a69585503bfb08243aa144b14a8..bbde257d65822ed09fd45c8f040f322dab5a795a 100644
--- a/lib/config/definitions.ts
+++ b/lib/config/definitions.ts
@@ -1456,32 +1456,6 @@ const options: RenovateOptions[] = [
     type: 'object',
     default: {
       versioning: dockerVersioning.id,
-      managerBranchPrefix: 'docker-',
-      commitMessageTopic: '{{{depName}}} Docker tag',
-      major: { enabled: false },
-      commitMessageExtra:
-        'to v{{#if isMajor}}{{{newMajor}}}{{else}}{{{newVersion}}}{{/if}}',
-      digest: {
-        branchTopic: '{{{depNameSanitized}}}-{{{currentValue}}}',
-        commitMessageExtra: 'to {{newDigestShort}}',
-        commitMessageTopic:
-          '{{{depName}}}{{#if currentValue}}:{{{currentValue}}}{{/if}} Docker digest',
-        group: {
-          commitMessageTopic: '{{{groupName}}}',
-          commitMessageExtra: '',
-        },
-      },
-      pin: {
-        commitMessageExtra: '',
-        groupName: 'Docker digests',
-        group: {
-          commitMessageTopic: '{{{groupName}}}',
-          branchTopic: 'digests-pin',
-        },
-      },
-      group: {
-        commitMessageTopic: '{{{groupName}}} Docker tags',
-      },
     },
     mergeable: true,
     cli: false,
diff --git a/lib/datasource/common.ts b/lib/datasource/common.ts
index 8ae1040dbe2812eb4c4944b0eb34bec2862ac2ae..9b9037a8866ce00caaa0a925de5358003df304fe 100644
--- a/lib/datasource/common.ts
+++ b/lib/datasource/common.ts
@@ -70,6 +70,7 @@ export interface Datasource {
   getReleases(config: GetReleasesConfig): Promise<ReleaseResult | null>;
   defaultRegistryUrls?: string[];
   appendRegistryUrls?: string[];
+  defaultConfig?: object;
 }
 
 export class DatasourceError extends Error {
diff --git a/lib/datasource/docker/index.ts b/lib/datasource/docker/index.ts
index 9d12ed7da6624a7c4e4fbc1aa117611f199ac15d..acc5411fac6412857a8eca1dbb07c67808dee46d 100644
--- a/lib/datasource/docker/index.ts
+++ b/lib/datasource/docker/index.ts
@@ -16,6 +16,35 @@ import { HostRule } from '../../types';
 
 export const id = 'docker';
 
+export const defaultConfig = {
+  managerBranchPrefix: 'docker-',
+  commitMessageTopic: '{{{depName}}} Docker tag',
+  major: { enabled: false },
+  commitMessageExtra:
+    'to v{{#if isMajor}}{{{newMajor}}}{{else}}{{{newVersion}}}{{/if}}',
+  digest: {
+    branchTopic: '{{{depNameSanitized}}}-{{{currentValue}}}',
+    commitMessageExtra: 'to {{newDigestShort}}',
+    commitMessageTopic:
+      '{{{depName}}}{{#if currentValue}}:{{{currentValue}}}{{/if}} Docker digest',
+    group: {
+      commitMessageTopic: '{{{groupName}}}',
+      commitMessageExtra: '',
+    },
+  },
+  pin: {
+    commitMessageExtra: '',
+    groupName: 'Docker digests',
+    group: {
+      commitMessageTopic: '{{{groupName}}}',
+      branchTopic: 'digests-pin',
+    },
+  },
+  group: {
+    commitMessageTopic: '{{{groupName}}} Docker tags',
+  },
+};
+
 const http = new Http(id);
 
 const ecrRegex = /\d+\.dkr\.ecr\.([-a-z0-9]+)\.amazonaws\.com/;
diff --git a/lib/datasource/index.ts b/lib/datasource/index.ts
index 7eb1ca8dc0cf64e6fff7cdb9cc442b580177bae2..1e277e1f1b25650f8c975201be3e4b9d54aed261 100644
--- a/lib/datasource/index.ts
+++ b/lib/datasource/index.ts
@@ -129,3 +129,8 @@ export async function getDigest(
     value
   );
 }
+
+export async function getDefaultConfig(datasource: string): Promise<object> {
+  const loadedDatasource = await load(datasource);
+  return loadedDatasource?.defaultConfig || {};
+}
diff --git a/lib/manager/circleci/__snapshots__/extract.spec.ts.snap b/lib/manager/circleci/__snapshots__/extract.spec.ts.snap
index d9dc36298d4f5cfd33ca5d69da640d6b0cd50dfc..825af9c96d4ea318b456dd91c65410ee09a9a350 100644
--- a/lib/manager/circleci/__snapshots__/extract.spec.ts.snap
+++ b/lib/manager/circleci/__snapshots__/extract.spec.ts.snap
@@ -12,6 +12,7 @@ Array [
     "managerData": Object {
       "lineNumber": 12,
     },
+    "versioning": "docker",
   },
   Object {
     "commitMessageTopic": "Node.js",
@@ -23,6 +24,7 @@ Array [
     "managerData": Object {
       "lineNumber": 57,
     },
+    "versioning": "docker",
   },
   Object {
     "commitMessageTopic": "Node.js",
@@ -34,6 +36,7 @@ Array [
     "managerData": Object {
       "lineNumber": 61,
     },
+    "versioning": "docker",
   },
   Object {
     "commitMessageTopic": "Node.js",
@@ -45,6 +48,7 @@ Array [
     "managerData": Object {
       "lineNumber": 65,
     },
+    "versioning": "docker",
   },
 ]
 `;
@@ -99,6 +103,7 @@ Array [
     "managerData": Object {
       "lineNumber": 20,
     },
+    "versioning": "docker",
   },
   Object {
     "currentDigest": "sha256:3870d35b962a943df72d948580fc66ceaaee1c4fbd205930f32e0f0760eb1077",
@@ -109,6 +114,7 @@ Array [
     "managerData": Object {
       "lineNumber": 27,
     },
+    "versioning": "docker",
   },
   Object {
     "currentDigest": "sha256:3870d35b962a943df72d948580fc66ceaaee1c4fbd205930f32e0f0760eb1077",
@@ -119,6 +125,7 @@ Array [
     "managerData": Object {
       "lineNumber": 34,
     },
+    "versioning": "docker",
   },
   Object {
     "currentDigest": "sha256:3870d35b962a943df72d948580fc66ceaaee1c4fbd205930f32e0f0760eb1077",
@@ -129,6 +136,7 @@ Array [
     "managerData": Object {
       "lineNumber": 41,
     },
+    "versioning": "docker",
   },
   Object {
     "currentDigest": "sha256:eb6325b75c1c70b4992eaa1bdd29e24e5f14d5324b4714a49f3e67783473214b",
@@ -139,6 +147,7 @@ Array [
     "managerData": Object {
       "lineNumber": 50,
     },
+    "versioning": "docker",
   },
   Object {
     "currentDigest": "sha256:3870d35b962a943df72d948580fc66ceaaee1c4fbd205930f32e0f0760eb1077",
@@ -149,6 +158,7 @@ Array [
     "managerData": Object {
       "lineNumber": 57,
     },
+    "versioning": "docker",
   },
 ]
 `;
diff --git a/lib/manager/circleci/extract.ts b/lib/manager/circleci/extract.ts
index ab866a5bcc98ee885437a78d44af0f3278833e21..71a0bbd1ab6339bcec52bd0f0320fb8a17533df8 100644
--- a/lib/manager/circleci/extract.ts
+++ b/lib/manager/circleci/extract.ts
@@ -53,6 +53,7 @@ export function extractPackageFile(content: string): PackageFile | null {
           'CircleCI docker image'
         );
         dep.depType = 'docker';
+        dep.versioning = 'docker';
         dep.managerData = { lineNumber };
         deps.push(dep);
       }
diff --git a/lib/manager/circleci/index.ts b/lib/manager/circleci/index.ts
index 3ed943c3156ac4fc686507486f8a853e3660e471..5695fc3a5323f09437e16e6070de90b43fe1640f 100644
--- a/lib/manager/circleci/index.ts
+++ b/lib/manager/circleci/index.ts
@@ -1,10 +1,7 @@
 import { extractPackageFile } from './extract';
 import { updateDependency } from './update';
-import { LANGUAGE_DOCKER } from '../../constants/languages';
 
-const language = LANGUAGE_DOCKER;
-
-export { extractPackageFile, language, updateDependency };
+export { extractPackageFile, updateDependency };
 
 export const defaultConfig = {
   fileMatch: ['(^|/).circleci/config.yml$'],
diff --git a/lib/workers/repository/process/extract-update.spec.ts b/lib/workers/repository/process/extract-update.spec.ts
index 7124d1c2d679086a44299c637001a0a31d245994..fe44bf28e7b38327c876a21327c677fd82828630 100644
--- a/lib/workers/repository/process/extract-update.spec.ts
+++ b/lib/workers/repository/process/extract-update.spec.ts
@@ -10,7 +10,7 @@ jest.mock('../extract');
 
 const branchify = mocked(_branchify);
 
-branchify.branchifyUpgrades.mockReturnValueOnce({
+branchify.branchifyUpgrades.mockResolvedValueOnce({
   branches: [],
   branchList: [],
 });
diff --git a/lib/workers/repository/process/extract-update.ts b/lib/workers/repository/process/extract-update.ts
index a53c71665aa2a43029354fd75821a1d926ec3911..5e258e56f3f37fd6776c70dca1fa74dcd792c5fb 100644
--- a/lib/workers/repository/process/extract-update.ts
+++ b/lib/workers/repository/process/extract-update.ts
@@ -25,7 +25,10 @@ export async function extractAndUpdate(
   await fetchUpdates(config, packageFiles);
   logger.debug({ config: packageFiles }, 'packageFiles with updates');
   await raiseDeprecationWarnings(config, packageFiles);
-  const { branches, branchList } = branchifyUpgrades(config, packageFiles);
+  const { branches, branchList } = await branchifyUpgrades(
+    config,
+    packageFiles
+  );
   sortBranches(branches);
   let res: WriteUpdateResult | undefined;
   // istanbul ignore else
diff --git a/lib/workers/repository/process/fetch.ts b/lib/workers/repository/process/fetch.ts
index bb445a933c0072d90331716011090dde4a67a194..d4b9aa11bad31966f173f1b444d08635a2041caf 100644
--- a/lib/workers/repository/process/fetch.ts
+++ b/lib/workers/repository/process/fetch.ts
@@ -75,7 +75,6 @@ async function fetchDepUpdates(
       currentValue,
       updates: dep.updates,
     });
-    logger.debug({ packageFile, depName }, 'fetchDepUpdates finished');
   }
   /* eslint-enable no-param-reassign */
 }
diff --git a/lib/workers/repository/updates/branchify.spec.ts b/lib/workers/repository/updates/branchify.spec.ts
index cdcdd58ac76ed21c868072d41a7e41ca023c9700..dd793fee8a9ee288fa08806940d9d566308089d5 100644
--- a/lib/workers/repository/updates/branchify.spec.ts
+++ b/lib/workers/repository/updates/branchify.spec.ts
@@ -16,13 +16,13 @@ beforeEach(() => {
 
 describe('workers/repository/updates/branchify', () => {
   describe('branchifyUpgrades()', () => {
-    it('returns empty', () => {
-      flattenUpdates.mockReturnValueOnce([]);
-      const res = branchifyUpgrades(config, {});
+    it('returns empty', async () => {
+      flattenUpdates.mockResolvedValueOnce([]);
+      const res = await branchifyUpgrades(config, {});
       expect(res.branches).toEqual([]);
     });
-    it('returns one branch if one input', () => {
-      flattenUpdates.mockReturnValueOnce([
+    it('returns one branch if one input', async () => {
+      flattenUpdates.mockResolvedValueOnce([
         {
           depName: 'foo',
           branchName: 'foo-{{version}}',
@@ -32,13 +32,13 @@ describe('workers/repository/updates/branchify', () => {
         },
       ]);
       config.repoIsOnboarded = true;
-      const res = branchifyUpgrades(config, {});
+      const res = await branchifyUpgrades(config, {});
       expect(Object.keys(res.branches)).toHaveLength(1);
       expect(res.branches[0].isMinor).toBe(true);
       expect(res.branches[0].upgrades[0].isMinor).toBe(true);
     });
-    it('uses major/minor/patch slugs', () => {
-      flattenUpdates.mockReturnValueOnce([
+    it('uses major/minor/patch slugs', async () => {
+      flattenUpdates.mockResolvedValueOnce([
         {
           depName: 'foo',
           branchName: 'foo-{{version}}',
@@ -85,7 +85,7 @@ describe('workers/repository/updates/branchify', () => {
         },
       ]);
       config.repoIsOnboarded = true;
-      const res = branchifyUpgrades(config, {});
+      const res = await branchifyUpgrades(config, {});
       expect(Object.keys(res.branches)).toHaveLength(4);
       expect(res.branches[0].isMajor).toBe(true);
       expect(res.branches[0].groupSlug).toBe(`major-some-packages`);
@@ -96,8 +96,8 @@ describe('workers/repository/updates/branchify', () => {
       expect(res.branches[3].isMajor).toBe(true);
       expect(res.branches[3].groupSlug).toBe(`major-2-other-packages`);
     });
-    it('does not group if different compiled branch names', () => {
-      flattenUpdates.mockReturnValueOnce([
+    it('does not group if different compiled branch names', async () => {
+      flattenUpdates.mockResolvedValueOnce([
         {
           depName: 'foo',
           branchName: 'foo-{{version}}',
@@ -117,11 +117,11 @@ describe('workers/repository/updates/branchify', () => {
           prTitle: 'some-title',
         },
       ]);
-      const res = branchifyUpgrades(config, {});
+      const res = await branchifyUpgrades(config, {});
       expect(Object.keys(res.branches)).toHaveLength(3);
     });
-    it('groups if same compiled branch names', () => {
-      flattenUpdates.mockReturnValueOnce([
+    it('groups if same compiled branch names', async () => {
+      flattenUpdates.mockResolvedValueOnce([
         {
           depName: 'foo',
           branchName: 'foo',
@@ -141,11 +141,11 @@ describe('workers/repository/updates/branchify', () => {
           prTitle: 'some-title',
         },
       ]);
-      const res = branchifyUpgrades(config, {});
+      const res = await branchifyUpgrades(config, {});
       expect(Object.keys(res.branches)).toHaveLength(2);
     });
-    it('groups if same compiled group name', () => {
-      flattenUpdates.mockReturnValueOnce([
+    it('groups if same compiled group name', async () => {
+      flattenUpdates.mockResolvedValueOnce([
         {
           depName: 'foo',
           branchName: 'foo',
@@ -169,10 +169,10 @@ describe('workers/repository/updates/branchify', () => {
           group: { branchName: 'renovate/my-group' },
         },
       ]);
-      const res = branchifyUpgrades(config, {});
+      const res = await branchifyUpgrades(config, {});
       expect(Object.keys(res.branches)).toHaveLength(2);
     });
-    it('enforces valid git branch name', () => {
+    it('enforces valid git branch name', async () => {
       const fixtures = [
         {
           upgrade: {
@@ -232,11 +232,11 @@ describe('workers/repository/updates/branchify', () => {
           expectedBranchName: 'renovate/bad-branch-name9',
         },
       ];
-      flattenUpdates.mockReturnValueOnce(
+      flattenUpdates.mockResolvedValueOnce(
         fixtures.map(({ upgrade }) => upgrade)
       );
 
-      branchifyUpgrades(config, {}).branches.forEach(
+      (await branchifyUpgrades(config, {})).branches.forEach(
         ({ branchName }, index: number) => {
           expect(branchName).toBe(fixtures[index].expectedBranchName);
         }
diff --git a/lib/workers/repository/updates/branchify.ts b/lib/workers/repository/updates/branchify.ts
index ef6b4cd741e570eab4ec81774663150d497e28bc..e599dfacadd75254ee331a9ee9e1a03b6f813b83 100644
--- a/lib/workers/repository/updates/branchify.ts
+++ b/lib/workers/repository/updates/branchify.ts
@@ -30,12 +30,12 @@ export type BranchifiedConfig = Merge<
     branchList: string[];
   }
 >;
-export function branchifyUpgrades(
+export async function branchifyUpgrades(
   config: RenovateConfig,
   packageFiles: Record<string, any[]>
-): BranchifiedConfig {
+): Promise<BranchifiedConfig> {
   logger.debug('branchifyUpgrades');
-  const updates = flattenUpdates(config, packageFiles);
+  const updates = await flattenUpdates(config, packageFiles);
   logger.debug(
     `${updates.length} flattened updates found: ${updates
       .map(u => u.depName)
diff --git a/lib/workers/repository/updates/flatten.spec.ts b/lib/workers/repository/updates/flatten.spec.ts
index dbd222c33b6734562691c59afd70d8a1172b0de7..a75a12a83ef02e13fa86d7b4ee30b49aa1b984ae 100644
--- a/lib/workers/repository/updates/flatten.spec.ts
+++ b/lib/workers/repository/updates/flatten.spec.ts
@@ -13,7 +13,7 @@ beforeEach(() => {
 
 describe('workers/repository/updates/flatten', () => {
   describe('flattenUpdates()', () => {
-    it('flattens', () => {
+    it('flattens', async () => {
       config.lockFileMaintenance.enabled = true;
       config.packageRules = [
         {
@@ -72,7 +72,7 @@ describe('workers/repository/updates/flatten', () => {
           },
         ],
       };
-      const res = flattenUpdates(config, packageFiles);
+      const res = await flattenUpdates(config, packageFiles);
       expect(res).toHaveLength(9);
       expect(
         res.filter(r => r.updateType === 'lockFileMaintenance')
diff --git a/lib/workers/repository/updates/flatten.ts b/lib/workers/repository/updates/flatten.ts
index 79258d50c89e3d9ec15c5f8515b5c640544d2dfd..7356951751b06b8c14c9200e768aa5dbe2784652 100644
--- a/lib/workers/repository/updates/flatten.ts
+++ b/lib/workers/repository/updates/flatten.ts
@@ -9,16 +9,17 @@ import {
 import { applyPackageRules } from '../../../util/package-rules';
 import { get } from '../../../manager';
 import { LANGUAGE_DOCKER } from '../../../constants/languages';
+import { getDefaultConfig } from '../../../datasource';
 
 // Return only rules that contain an updateType
 function getUpdateTypeRules(packageRules: PackageRule[]): PackageRule[] {
   return packageRules.filter(rule => is.nonEmptyArray(rule.updateTypes));
 }
 
-export function flattenUpdates(
+export async function flattenUpdates(
   config: RenovateConfig,
   packageFiles: Record<string, any[]>
-): RenovateConfig[] {
+): Promise<RenovateConfig[]> {
   const updates = [];
   const updateTypes = [
     'major',
@@ -39,6 +40,11 @@ export function flattenUpdates(
           for (const update of dep.updates) {
             let updateConfig = mergeChildConfig(depConfig, update);
             delete updateConfig.updates;
+            // apply config from datasource
+            const datasourceConfig = await getDefaultConfig(
+              depConfig.datasource
+            );
+            updateConfig = mergeChildConfig(updateConfig, datasourceConfig);
             updateConfig = applyPackageRules(updateConfig);
             // Keep only rules that haven't been applied yet (with updateTypes)
             updateConfig.packageRules = getUpdateTypeRules(