diff --git a/lib/util/git/index.ts b/lib/util/git/index.ts
index 6122d20755ff0a175373cc203a443c4ab6ad1dc7..b8104496f1a5a5ca33d3526c370204ac43b5aba8 100644
--- a/lib/util/git/index.ts
+++ b/lib/util/git/index.ts
@@ -17,7 +17,7 @@ import {
 import { logger } from '../../logger';
 import { ExternalHostError } from '../../types/errors/external-host-error';
 import { GitOptions, GitProtocol } from '../../types/git';
-import * as limits from '../../workers/global/limits';
+import { Limit, incLimitedValue } from '../../workers/global/limits';
 import { writePrivateKey } from './private-key';
 
 export * from './private-key';
@@ -455,7 +455,7 @@ export async function mergeBranch(branchName: string): Promise<void> {
   await git.checkout(config.currentBranch);
   await git.merge(['--ff-only', branchName]);
   await git.push('origin', config.currentBranch);
-  limits.incrementLimit('prCommitsPerRunLimit');
+  incLimitedValue(Limit.Commits);
 }
 
 export async function getBranchLastCommitTime(
@@ -604,7 +604,7 @@ export async function commitFiles({
     await git.fetch(['origin', ref, '--depth=2', '--force']);
     config.branchCommits[branchName] = commit;
     config.branchIsModified[branchName] = false;
-    limits.incrementLimit('prCommitsPerRunLimit');
+    incLimitedValue(Limit.Commits);
     return commit;
   } catch (err) /* istanbul ignore next */ {
     checkForPlatformFailure(err);
diff --git a/lib/workers/global/index.spec.ts b/lib/workers/global/index.spec.ts
index f58c0a58fdcbfe5d37de0b792fadd67c01ecd393..b79eef90536cccf64c73cd307a2164d7f7da7322 100644
--- a/lib/workers/global/index.spec.ts
+++ b/lib/workers/global/index.spec.ts
@@ -59,7 +59,7 @@ describe('lib/workers/global', () => {
   });
 
   it('processes repositories break', async () => {
-    limits.getLimitRemaining = jest.fn(() => 0);
+    limits.isLimitReached = jest.fn(() => true);
     configParser.parseConfigs.mockResolvedValueOnce({
       gitAuthor: 'a@b.com',
       enabled: true,
diff --git a/lib/workers/global/index.ts b/lib/workers/global/index.ts
index 2629360c9025e53933ce1c41cc77d1f700afc15e..6e353acf06fd8a89914b3ccc9c6ab87ec7790bcd 100644
--- a/lib/workers/global/index.ts
+++ b/lib/workers/global/index.ts
@@ -8,7 +8,7 @@ import * as hostRules from '../../util/host-rules';
 import * as repositoryWorker from '../repository';
 import { autodiscoverRepositories } from './autodiscover';
 import { globalFinalize, globalInitialize } from './initialize';
-import * as limits from './limits';
+import { Limit, isLimitReached } from './limits';
 
 type RenovateConfig = configParser.RenovateConfig;
 type RenovateRepository = configParser.RenovateRepository;
@@ -35,7 +35,7 @@ function getGlobalConfig(): Promise<RenovateConfig> {
 }
 
 function haveReachedLimits(): boolean {
-  if (limits.getLimitRemaining('prCommitsPerRunLimit') <= 0) {
+  if (isLimitReached(Limit.Commits)) {
     logger.info('Max commits created for this run.');
     return true;
   }
diff --git a/lib/workers/global/initialize.ts b/lib/workers/global/initialize.ts
index f575084b75e4464ad6c7ad7dc955af9106966bc9..dc2e34d39bfcece645ed7b11421e5cc522c8bda3 100644
--- a/lib/workers/global/initialize.ts
+++ b/lib/workers/global/initialize.ts
@@ -6,7 +6,7 @@ import { logger } from '../../logger';
 import { initPlatform } from '../../platform';
 import * as packageCache from '../../util/cache/package';
 import { setEmojiConfig } from '../../util/emoji';
-import * as limits from './limits';
+import { Limit, setMaxLimit } from './limits';
 
 async function setDirectories(input: RenovateConfig): Promise<RenovateConfig> {
   const config: RenovateConfig = { ...input };
@@ -35,7 +35,7 @@ export async function globalInitialize(
   config = await initPlatform(config);
   config = await setDirectories(config);
   packageCache.init(config);
-  limits.init(config);
+  setMaxLimit(Limit.Commits, config.prCommitsPerRunLimit);
   setEmojiConfig(config);
   return config;
 }
diff --git a/lib/workers/global/limits.spec.ts b/lib/workers/global/limits.spec.ts
index 6e89bc7a69351d5132efac9f22480cdac6aa4957..d2a4ad8b6b2ae5e2ee77a4675d8daa6da8c59ccd 100644
--- a/lib/workers/global/limits.spec.ts
+++ b/lib/workers/global/limits.spec.ts
@@ -1,21 +1,43 @@
-import { getLimitRemaining, incrementLimit, init } from './limits';
+import {
+  Limit,
+  incLimitedValue,
+  isLimitReached,
+  resetAllLimits,
+  setMaxLimit,
+} from './limits';
 
 describe('lib/workers/global/limits', () => {
-  describe('init()', () => {
-    it('check defined variables have a value set to zero', () => {
-      const config = { prCommitsPerRunLimit: 3 };
-      init(config);
-      const result = getLimitRemaining('prCommitsPerRunLimit');
-      expect(result).toEqual(3);
-    });
+  beforeEach(() => {
+    resetAllLimits();
   });
-  describe('incrementLimit()', () => {
-    it('check increment works as expected', () => {
-      const config = { prCommitsPerRunLimit: 3 };
-      init(config);
-      incrementLimit('prCommitsPerRunLimit', 2);
-      const result = getLimitRemaining('prCommitsPerRunLimit');
-      expect(result).toEqual(1);
-    });
+
+  beforeEach(() => {
+    resetAllLimits();
+  });
+
+  it('increments limited value', () => {
+    setMaxLimit(Limit.Commits, 3);
+
+    expect(isLimitReached(Limit.Commits)).toBe(false);
+
+    incLimitedValue(Limit.Commits, 2);
+    expect(isLimitReached(Limit.Commits)).toBe(false);
+
+    incLimitedValue(Limit.Commits);
+    expect(isLimitReached(Limit.Commits)).toBe(true);
+
+    incLimitedValue(Limit.Commits);
+    expect(isLimitReached(Limit.Commits)).toBe(true);
+  });
+
+  it('defaults to unlimited', () => {
+    expect(isLimitReached(Limit.Commits)).toBe(false);
+  });
+
+  it('increments undefined', () => {
+    incLimitedValue(Limit.Commits);
+    expect(isLimitReached(Limit.Commits)).toBe(false);
+    setMaxLimit(Limit.Commits, 1);
+    expect(isLimitReached(Limit.Commits)).toBe(true);
   });
 });
diff --git a/lib/workers/global/limits.ts b/lib/workers/global/limits.ts
index 0cf7d3052da9f32f16f4ebb19a66032b510d02db..5bb983bb09aa823e0845972a501a11ed81fc47c9 100644
--- a/lib/workers/global/limits.ts
+++ b/lib/workers/global/limits.ts
@@ -1,41 +1,44 @@
 import { logger } from '../../logger';
 
-const limitsToInit = ['prCommitsPerRunLimit'];
-const l: Record<string, number> = {};
-const v: Record<string, number> = {};
+export enum Limit {
+  Commits = 'Commits',
+}
 
-export function setLimit(name: string, value: number): void {
-  logger.debug(`Limits.setLimit l[${name}] = ${value}`);
-  l[name] = value;
+interface LimitValue {
+  max: number | null;
+  current: number;
 }
 
-export function init(config: Record<string, any>): void {
-  logger.debug(`Limits.init enter method`);
-  for (const limit of limitsToInit) {
-    logger.debug(`Limits.init ${limit} processing`);
-    if (config[limit]) {
-      setLimit(limit, config[limit]);
-      v[limit] = 0;
-    } else {
-      logger.debug(
-        `Limits.init ${limit} variable is not set. Ignoring ${limit}`
-      );
-    }
-  }
+const limits = new Map<Limit, LimitValue>();
+
+export function resetAllLimits(): void {
+  limits.clear();
 }
 
-export function getLimitRemaining(name: string): number {
-  let result;
-  if (typeof v[name] !== 'undefined') {
-    result = l[name] - v[name];
-  } else {
-    result = undefined;
-  }
-  return result;
+export function setMaxLimit(key: Limit, max: unknown): void {
+  const maxVal = typeof max === 'number' && max > 0 ? max : null;
+  logger.debug(`${key} limit = ${maxVal}`);
+  const limit = limits.get(key);
+  limits.set(key, {
+    current: 0,
+    ...limit,
+    max: maxVal,
+  });
+}
+
+export function incLimitedValue(key: Limit, incBy = 1): void {
+  const limit = limits.get(key) || { max: null, current: 0 };
+  limits.set(key, {
+    ...limit,
+    current: limit.current + incBy,
+  });
 }
 
-export function incrementLimit(name: string, value = 1): void {
-  if (typeof v[name] !== 'undefined') {
-    v[name] += value;
+export function isLimitReached(key: Limit): boolean {
+  const limit = limits.get(key);
+  if (!limit || limit.max === null) {
+    return false;
   }
+  const { max, current } = limit;
+  return max - current <= 0;
 }
diff --git a/lib/workers/repository/process/write.ts b/lib/workers/repository/process/write.ts
index e127fa10ca21b97da9e93a7f408b25f4248ac409..424653d380c66df5063b0a08b91ff7ceaedd0bd4 100644
--- a/lib/workers/repository/process/write.ts
+++ b/lib/workers/repository/process/write.ts
@@ -2,7 +2,7 @@ import { RenovateConfig } from '../../../config';
 import { addMeta, logger, removeMeta } from '../../../logger';
 import { processBranch } from '../../branch';
 import { BranchConfig, ProcessBranchResult } from '../../common';
-import { getLimitRemaining } from '../../global/limits';
+import { Limit, isLimitReached } from '../../global/limits';
 import { getPrsRemaining } from './limits';
 
 export type WriteUpdateResult = 'done' | 'automerged';
@@ -32,7 +32,7 @@ export async function writeUpdates(
   for (const branch of branches) {
     addMeta({ branch: branch.branchName });
     const prLimitReached = prsRemaining <= 0;
-    const commitLimitReached = getLimitRemaining('prCommitsPerRunLimit') <= 0;
+    const commitLimitReached = isLimitReached(Limit.Commits);
     const res = await processBranch(branch, prLimitReached, commitLimitReached);
     branch.res = res;
     if (