diff --git a/lib/config/definitions.spec.ts b/lib/config/definitions.spec.ts
index 99517cfdd251cb7f5e9a7ff7dbfdbc3f62f21974..55b5330e80783acdba2dd1a3a873dc045b3e8d54 100644
--- a/lib/config/definitions.spec.ts
+++ b/lib/config/definitions.spec.ts
@@ -2,7 +2,7 @@ import { getOptions } from './definitions';
 import { getName } from '../../test/util';
 
 jest.mock('../manager', () => ({
-  getManagers: jest.fn(() => ({ testManager: {} })),
+  getManagers: jest.fn(() => new Map().set('testManager', {})),
 }));
 
 describe(getName(__filename), () => {
diff --git a/lib/config/definitions.ts b/lib/config/definitions.ts
index 53e22359bfc983960651575fbc69db7e3871af99..02ce9bcf069eb89ed1834e38340843f7ad660968 100644
--- a/lib/config/definitions.ts
+++ b/lib/config/definitions.ts
@@ -1738,7 +1738,7 @@ export function getOptions(): RenovateOptions[] {
 }
 
 function loadManagerOptions(): void {
-  for (const [name, config] of Object.entries(getManagers())) {
+  for (const [name, config] of getManagers().entries()) {
     if (config.defaultConfig) {
       const managerConfig: RenovateOptions = {
         name,
diff --git a/lib/manager/index.spec.ts b/lib/manager/index.spec.ts
index 352263e2b484bdb36f792c9d29a54b53a25bd5c5..06fb46d22724ef5ada790bd319e7f330d4dd7422 100644
--- a/lib/manager/index.spec.ts
+++ b/lib/manager/index.spec.ts
@@ -1,4 +1,6 @@
 import * as manager from '.';
+import { ManagerApi } from './common';
+import { loadModules } from '../util/modules';
 
 describe('manager', () => {
   describe('get()', () => {
@@ -16,28 +18,127 @@ describe('manager', () => {
       expect(manager.getManagerList()).not.toBeNull();
     });
   });
+
+  it('validates', () => {
+    function validate(module: ManagerApi): boolean {
+      if (!module.defaultConfig) {
+        return false;
+      }
+      if (!module.updateDependency && !module.autoReplace) {
+        return false;
+      }
+      if (!module.extractPackageFile && !module.extractAllPackageFiles) {
+        return false;
+      }
+      return true;
+    }
+    const mgrs = manager.getManagers();
+
+    const loadedMgr = loadModules(__dirname, validate);
+    expect(Array.from(mgrs.keys())).toEqual(Object.keys(loadedMgr));
+
+    for (const name of mgrs.keys()) {
+      const mgr = mgrs.get(name);
+      expect(validate(mgr)).toBe(true);
+    }
+  });
+
   describe('extractAllPackageFiles()', () => {
     it('returns null', () => {
+      manager.getManagers().set('dummy', {
+        defaultConfig: {},
+      });
       expect(
-        manager.extractAllPackageFiles('dockerfile', {} as any, [])
+        manager.extractAllPackageFiles('unknown', {} as any, [])
       ).toBeNull();
+      expect(manager.extractAllPackageFiles('dummy', {} as any, [])).toBeNull();
     });
     it('returns non-null', () => {
+      manager.getManagers().set('dummy', {
+        defaultConfig: {},
+        extractAllPackageFiles: () => Promise.resolve([]),
+      });
       expect(
-        manager.extractAllPackageFiles('npm', {} as any, [])
+        manager.extractAllPackageFiles('dummy', {} as any, [])
       ).not.toBeNull();
     });
+    afterEach(() => {
+      manager.getManagers().delete('dummy');
+    });
   });
 
   describe('extractPackageFile()', () => {
     it('returns null', () => {
+      manager.getManagers().set('dummy', {
+        defaultConfig: {},
+      });
       expect(manager.extractPackageFile('unknown', null)).toBeNull();
+      expect(manager.extractPackageFile('dummy', null)).toBeNull();
+    });
+    it('returns non-null', () => {
+      manager.getManagers().set('dummy', {
+        defaultConfig: {},
+        extractPackageFile: () => Promise.resolve({ deps: [] }),
+      });
+
+      expect(manager.extractPackageFile('dummy', null)).not.toBeNull();
+    });
+    afterEach(() => {
+      manager.getManagers().delete('dummy');
     });
   });
 
   describe('getPackageUpdates', () => {
     it('returns null', () => {
+      manager.getManagers().set('dummy', {
+        defaultConfig: {},
+      });
       expect(manager.getPackageUpdates('unknown', null)).toBeNull();
+      expect(manager.getPackageUpdates('dummy', null)).toBeNull();
+    });
+    it('returns non-null', () => {
+      manager.getManagers().set('dummy', {
+        defaultConfig: {},
+        getPackageUpdates: () => Promise.resolve([]),
+      });
+      expect(manager.getPackageUpdates('dummy', {} as any)).not.toBeNull();
+    });
+    afterEach(() => {
+      manager.getManagers().delete('dummy');
+    });
+  });
+
+  describe('getRangeStrategy', () => {
+    it('returns null', () => {
+      manager.getManagers().set('dummy', {
+        defaultConfig: {},
+      });
+      expect(
+        manager.getRangeStrategy({ manager: 'unknown', rangeStrategy: 'auto' })
+      ).toBeNull();
+    });
+    it('returns non-null', () => {
+      manager.getManagers().set('dummy', {
+        defaultConfig: {},
+        getRangeStrategy: () => 'replace',
+      });
+      expect(
+        manager.getRangeStrategy({ manager: 'dummy', rangeStrategy: 'auto' })
+      ).not.toBeNull();
+
+      manager.getManagers().set('dummy', {
+        defaultConfig: {},
+      });
+      expect(
+        manager.getRangeStrategy({ manager: 'dummy', rangeStrategy: 'auto' })
+      ).not.toBeNull();
+
+      expect(
+        manager.getRangeStrategy({ manager: 'dummy', rangeStrategy: 'bump' })
+      ).not.toBeNull();
+    });
+    afterEach(() => {
+      manager.getManagers().delete('dummy');
     });
   });
 });
diff --git a/lib/manager/index.ts b/lib/manager/index.ts
index 4d419aac9f1fbc9d3d82429ac0ebe05fc10a945c..65f28be55309df8bd1b070d24144d1f502468436 100644
--- a/lib/manager/index.ts
+++ b/lib/manager/index.ts
@@ -21,29 +21,9 @@ import {
   LANGUAGE_RUBY,
   LANGUAGE_RUST,
 } from '../constants/languages';
-import { loadModules } from '../util/modules';
-import { logger } from '../logger';
+import managers from './api.generated';
 
-// istanbul ignore next
-function validateManager(manager): boolean {
-  if (!manager.defaultConfig) {
-    logger.fatal(`manager is missing defaultConfig`);
-    return false;
-  }
-  if (!manager.updateDependency && !manager.autoReplace) {
-    logger.fatal(`manager is missing updateDependency`);
-    return false;
-  }
-  if (!manager.extractPackageFile && !manager.extractAllPackageFiles) {
-    logger.fatal(
-      `manager must support extractPackageFile or extractAllPackageFiles`
-    );
-  }
-  return true;
-}
-
-const managers = loadModules<ManagerApi>(__dirname, validateManager);
-const managerList = Object.keys(managers);
+const managerList = Array.from(managers.keys());
 
 const languageList = [
   LANGUAGE_DART,
@@ -59,21 +39,27 @@ const languageList = [
   LANGUAGE_RUST,
 ];
 
-export const get = <T extends keyof ManagerApi>(
+export function get<T extends keyof ManagerApi>(
   manager: string,
   name: T
-): ManagerApi[T] => managers[manager][name];
+): ManagerApi[T] | null {
+  return managers.get(manager)?.[name];
+}
 export const getLanguageList = (): string[] => languageList;
 export const getManagerList = (): string[] => managerList;
-export const getManagers = (): Record<string, ManagerApi> => managers;
+export const getManagers = (): Map<string, ManagerApi> => managers;
 
 export function extractAllPackageFiles(
   manager: string,
   config: ExtractConfig,
   files: string[]
 ): Result<PackageFile[] | null> {
-  return managers[manager] && managers[manager].extractAllPackageFiles
-    ? managers[manager].extractAllPackageFiles(config, files)
+  if (!managers.has(manager)) {
+    return null;
+  }
+  const m = managers.get(manager);
+  return m.extractAllPackageFiles
+    ? m.extractAllPackageFiles(config, files)
     : null;
 }
 
@@ -81,9 +67,11 @@ export function getPackageUpdates(
   manager: string,
   config: PackageUpdateConfig
 ): Result<PackageUpdateResult[]> | null {
-  return managers[manager] && managers[manager].getPackageUpdates
-    ? managers[manager].getPackageUpdates(config)
-    : null;
+  if (!managers.has(manager)) {
+    return null;
+  }
+  const m = managers.get(manager);
+  return m.getPackageUpdates ? m.getPackageUpdates(config) : null;
 }
 
 export function extractPackageFile(
@@ -92,16 +80,24 @@ export function extractPackageFile(
   fileName?: string,
   config?: ExtractConfig
 ): Result<PackageFile | null> {
-  return managers[manager] && managers[manager].extractPackageFile
-    ? managers[manager].extractPackageFile(content, fileName, config)
+  if (!managers.has(manager)) {
+    return null;
+  }
+  const m = managers.get(manager);
+  return m.extractPackageFile
+    ? m.extractPackageFile(content, fileName, config)
     : null;
 }
 
 export function getRangeStrategy(config: RangeConfig): RangeStrategy {
   const { manager, rangeStrategy } = config;
-  if (managers[manager].getRangeStrategy) {
+  if (!managers.has(manager)) {
+    return null;
+  }
+  const m = managers.get(manager);
+  if (m.getRangeStrategy) {
     // Use manager's own function if it exists
-    return managers[manager].getRangeStrategy(config);
+    return m.getRangeStrategy(config);
   }
   if (rangeStrategy === 'auto') {
     // default to 'replace' for auto
diff --git a/lib/util/exec/index.ts b/lib/util/exec/index.ts
index fd9f139119de442a34ef8e5e5f28e16ccccd3838..4dc0fa3fea5611e62bb3a5762508ee4e5202ba7a 100644
--- a/lib/util/exec/index.ts
+++ b/lib/util/exec/index.ts
@@ -17,7 +17,7 @@ import {
   Opt,
   DockerOptions,
 } from './common';
-import { RenovateConfig } from '../../config';
+import { RenovateConfig } from '../../config/common';
 
 const execConfig: ExecConfig = {
   binarySource: null,
diff --git a/package.json b/package.json
index bce12913d706612ca5c4c638e62ed5cc0545870f..7d4062b1dbc553267ceab740fafc3937a57584ed 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
     "compile:ts": "tsc -p tsconfig.app.json",
     "compile:dts": "tsc -p tsconfig.dts.json",
     "generate": "run-s generate:*",
-    "generate:imports": "node --experimental-modules tools/generate-imports.mjs",
+    "generate:imports": "node tmp/tools/generate-imports.js",
     "copy-static-files": "copyfiles -u 1 -e **/__fixtures__/**  -e **/__mocks__/** lib/**/*.json lib/**/*.py dist/",
     "create-json-schema": "babel-node --extensions \".ts,.js\" -- bin/create-json-schema.js && prettier --write \"renovate-schema.json\"",
     "debug": "babel-node --inspect-brk  --extensions \".ts,.js\" -- lib/renovate.ts",
diff --git a/tools/generate-imports.mjs b/tools/generate-imports.mjs
deleted file mode 100644
index df0b07fca70ad526d0af898f7b186cb040bbc8ff..0000000000000000000000000000000000000000
--- a/tools/generate-imports.mjs
+++ /dev/null
@@ -1,43 +0,0 @@
-import shell from 'shelljs';
-import fs from 'fs-extra';
-
-shell.echo('generating imports');
-const newFiles = new Set();
-
-if (!fs.existsSync('lib')) {
-  shell.echo('> missing sources');
-  shell.exit(0);
-}
-
-function findModules(dirname) {
-  return fs
-    .readdirSync(dirname, { withFileTypes: true })
-    .filter(dirent => dirent.isDirectory())
-    .map(dirent => dirent.name)
-    .filter(name => !name.startsWith('__'))
-    .sort();
-}
-function updateFile(file, code) {
-  const oldCode = fs.existsSync(file) ? fs.readFileSync(file) : null;
-  if (code !== oldCode) {
-    fs.writeFileSync(file, code);
-  }
-  newFiles.add(file);
-}
-
-let code = `
-import { Datasource } from './common';
-const api = new Map<string, Promise<Datasource>>();
-export default api;
-`;
-for (const ds of findModules('lib/datasource')) {
-  code += `api.set('${ds}', import('./${ds}'));\n`;
-}
-
-updateFile('lib/datasource/api.generated.ts', code);
-
-for (const file of shell
-  .find('lib/**/*.generated.ts')
-  .filter(f => !newFiles.has(f))) {
-  fs.removeSync(file);
-}
diff --git a/tools/generate-imports.ts b/tools/generate-imports.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c3f470ddfaca7f768dc6113a4faa00cd9cbe36e0
--- /dev/null
+++ b/tools/generate-imports.ts
@@ -0,0 +1,68 @@
+import shell from 'shelljs';
+import fs from 'fs-extra';
+import _ from 'lodash';
+
+shell.echo('generating imports');
+const newFiles = new Set();
+
+if (!fs.existsSync('lib')) {
+  shell.echo('> missing sources');
+  shell.exit(0);
+}
+
+function findModules(dirname: string): string[] {
+  return fs
+    .readdirSync(dirname, { withFileTypes: true })
+    .filter(dirent => dirent.isDirectory())
+    .map(dirent => dirent.name)
+    .filter(name => !name.startsWith('__'))
+    .sort();
+}
+async function updateFile(file: string, code: string): Promise<void> {
+  const oldCode = fs.existsSync(file) ? await fs.readFile(file, 'utf8') : null;
+  if (code !== oldCode) {
+    await fs.writeFile(file, code);
+  }
+  newFiles.add(file);
+}
+(async () => {
+  try {
+    shell.echo('> datasources');
+    let code = `
+import { Datasource } from './common';
+const api = new Map<string, Promise<Datasource>>();
+export default api;
+`;
+    for (const ds of findModules('lib/datasource')) {
+      code += `api.set('${ds}', import('./${ds}'));\n`;
+    }
+    await updateFile('lib/datasource/api.generated.ts', code);
+
+    shell.echo('> managers');
+    let imports = '';
+    let maps = '';
+    for (const ds of findModules('lib/manager')) {
+      const name = _.camelCase(ds);
+      imports += `import * as ${name} from './${ds}';\n`;
+      maps += `api.set('${ds}', ${name});\n`;
+    }
+
+    code = `import { ManagerApi } from './common';
+${imports}
+const api = new Map<string, ManagerApi>();
+export default api;
+${maps}`;
+
+    await updateFile('lib/manager/api.generated.ts', code);
+
+    await Promise.all(
+      shell
+        .find('lib/**/*.generated.ts')
+        .filter(f => !newFiles.has(f))
+        .map(file => fs.remove(file))
+    );
+  } catch (e) {
+    shell.echo(e.toString());
+    shell.exit(1);
+  }
+})();
diff --git a/tools/package.json b/tools/package.json
index 4831de9e1d33f3aaa41446c034dd4fefe071d88a..8d59bf3f6ba4c349e05fbae7a239c73e172035bc 100644
--- a/tools/package.json
+++ b/tools/package.json
@@ -10,6 +10,7 @@
     "commander": "4.1.1",
     "fs-extra": "8.1.0",
     "got": "9.6.0",
+    "lodash": "4.17.15",
     "shelljs": "0.8.3",
     "strip-ansi": "5.2.0"
   }