diff --git a/docs/configuration.md b/docs/configuration.md
index dc22d9aa838ef6d1dd7ad9b609719612d18d8e60..c6ca5d55258277aea1ecd1192cf902a230558e0f 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -84,7 +84,7 @@ $ node renovate --help
     --respect-latest [boolean]           Ignore versions newer than npm "latest" version
     --recreate-closed [boolean]          Recreate PRs even if same ones were closed previously
     --rebase-stale-prs [boolean]         Rebase stale PRs (GitHub only)
-    --maintain-yarn-lock [boolean]       Keep yarn.lock updated in base branch (no monorepo support)
+    --maintain-yarn-lock [boolean]       Keep yarn.lock files updated in base branch
     --group-name <string>                Human understandable name for the dependency group
     --group-slug <string>                Slug to use for group (e.g. in branch name). Will be calculated from groupName if null
     --labels <list>                      Labels to add to Pull Request
@@ -142,7 +142,7 @@ Obviously, you can't set repository or package file location with this method.
 | `commitMessage` | Commit message template | string | `"Update dependency {{depName}} to version {{newVersion}}"` |  |  |
 | `prTitle` | Pull Request title template | string | `"{{#if isPin}}Pin{{else}}Update{{/if}} dependency {{depName}} to version {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}{{newVersionMajor}}.x{{else}}{{newVersion}}{{/if}}{{/if}}"` |  |  |
 | `prBody` | Pull Request body template | string | `"This Pull Request updates dependency {{depName}} from version `{{currentVersion}}` to `{{newVersion}}`\n\n{{changelog}}"` |  |  |
-| `maintainYarnLock` | Keep yarn.lock updated in base branch (no monorepo support) | boolean | `false` | `RENOVATE_MAINTAIN_YARN_LOCK` | `--maintain-yarn-lock` |
+| `maintainYarnLock` | Keep yarn.lock files updated in base branch | boolean | `false` | `RENOVATE_MAINTAIN_YARN_LOCK` | `--maintain-yarn-lock` |
 | `yarnMaintenanceBranchName` | Branch name template when maintaining yarn.lock | string | `"renovate/yarn-lock"` |  |  |
 | `yarnMaintenanceCommitMessage` | Commit message template when maintaining yarn.lock | string | `"Renovate yarn.lock file"` |  |  |
 | `yarnMaintenancePrTitle` | Pull Request title template when maintaining yarn.lock | string | `"Renovate yarn.lock file"` |  |  |
diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index 683764ee94c92f55a82089c481742e5c2eadedbe..aa0c3f85155f7a1f3a1f764490f972857baceac2 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -123,7 +123,7 @@ const options = [
   // Yarn Lock Maintenance
   {
     name: 'maintainYarnLock',
-    description: 'Keep yarn.lock updated in base branch (no monorepo support)',
+    description: 'Keep yarn.lock files updated in base branch',
     type: 'boolean',
     default: false,
   },
diff --git a/lib/worker.js b/lib/worker.js
index d440a6cdd446da509217c233d019ae972a09c0d4..69bb958c7cbe693e8f969e6ee28b0600822243b6 100644
--- a/lib/worker.js
+++ b/lib/worker.js
@@ -1,5 +1,4 @@
 const logger = require('winston');
-const path = require('path');
 const stringify = require('json-stringify-pretty-compact');
 const githubApi = require('./api/github');
 const gitlabApi = require('./api/gitlab');
@@ -19,7 +18,6 @@ module.exports = {
   updateBranch,
   assignDepConfigs,
   getDepTypeConfig,
-  maintainYarnLock,
 };
 
 // This function manages the queue per-package file
@@ -67,7 +65,12 @@ async function processPackageFile(repoName, packageFile, packageConfig) {
   const upgrades = await findUpgrades(dependencies);
   // Process all upgrades sequentially
   if (config.maintainYarnLock) {
-    await maintainYarnLock(config);
+    const upgrade = Object.assign({}, config, { upgradeType: 'maintainYarnLock' });
+    upgrade.upgradeType = 'maintainYarnLock';
+    upgrade.branchName = upgrade.yarnMaintenanceBranchName;
+    upgrade.prTitle = upgrade.yarnMaintenancePrTitle;
+    upgrade.prBody = upgrade.yarnMaintenancePrBody;
+    upgrades.push(upgrade);
   }
   return upgrades;
 }
@@ -126,31 +129,6 @@ function getDepTypeConfig(depTypes, depTypeName) {
   return depTypeConfig;
 }
 
-async function maintainYarnLock(inputConfig) {
-  const packageContent = await inputConfig.api.getFileContent(inputConfig.packageFile);
-  const yarnLockFileName = path.join(path.dirname(inputConfig.packageFile), 'yarn.lock');
-  logger.debug(`Checking for ${yarnLockFileName}`);
-  const existingYarnLock = await inputConfig.api.getFileContent(yarnLockFileName);
-  if (!existingYarnLock) {
-    return;
-  }
-  logger.debug('Found existing yarn.lock file');
-  const newYarnLock = await branchWorker.getYarnLockFile(packageContent, inputConfig);
-  if (existingYarnLock === newYarnLock.contents) {
-    logger.debug('Yarn lock file does not need updating');
-    return;
-  }
-  logger.debug('Yarn lock needs updating');
-  // API will know whether to create new branch or not
-  const params = Object.assign({}, inputConfig);
-  const commitMessage = handlebars.compile(params.yarnMaintenanceCommitMessage)(params);
-  params.branchName = params.yarnMaintenanceBranchName;
-  params.prTitle = params.yarnMaintenancePrTitle;
-  params.prBody = params.yarnMaintenancePrBody;
-  await inputConfig.api.commitFilesToBranch(params.branchName, [newYarnLock], commitMessage);
-  prWorker.ensurePr(params);
-}
-
 async function findUpgrades(dependencies) {
   const allUpgrades = [];
   // findDepUpgrades can add more than one upgrade to allUpgrades
@@ -222,12 +200,15 @@ async function updateBranch(upgrades) {
   logger.verbose(`branchName '${branchName}' length is ${upgrades.length}`);
 
   try {
-    if (!upgrade0.recreateClosed && await upgrade0.api.checkForClosedPr(branchName, prTitle)) {
+    if (upgrade0.upgradeType !== 'maintainYarnLock' &&
+      !upgrade0.recreateClosed && await upgrade0.api.checkForClosedPr(branchName, prTitle)) {
       logger.verbose(`Skipping ${branchName} upgrade as matching closed PR already existed`);
       return;
     }
-    await branchWorker.ensureBranch(upgrades);
-    await prWorker.ensurePr(upgrade0);
+    const branchCreated = await branchWorker.ensureBranch(upgrades);
+    if (branchCreated) {
+      await prWorker.ensurePr(upgrade0);
+    }
   } catch (error) {
     logger.error(`Error updating branch ${branchName}: ${error}`);
     // Don't throw here - we don't want to stop the other renovations
diff --git a/lib/workers/branch.js b/lib/workers/branch.js
index 52a7a4d068bb3cf52aaa4709dbdbe58a53155a9c..eb65ba4b01e7107dfc4a47afaa26e19124b2e3b1 100644
--- a/lib/workers/branch.js
+++ b/lib/workers/branch.js
@@ -8,6 +8,7 @@ module.exports = {
   getParentBranch,
   getYarnLockFile,
   ensureBranch,
+  maintainYarnLock,
 };
 
 async function getParentBranch(branchName, config) {
@@ -70,6 +71,28 @@ async function getYarnLockFile(packageFile, packageContent, api) {
   });
 }
 
+async function maintainYarnLock(inputConfig) {
+  logger.debug(`maintainYarnLock(${JSON.stringify(inputConfig)})`);
+  const packageContent = await inputConfig.api.getFileContent(inputConfig.packageFile);
+  const yarnLockFileName = path.join(path.dirname(inputConfig.packageFile), 'yarn.lock');
+  logger.debug(`Checking for ${yarnLockFileName}`);
+  const existingYarnLock = await inputConfig.api.getFileContent(yarnLockFileName);
+  logger.silly(`existingYarnLock:\n${existingYarnLock}`);
+  if (!existingYarnLock) {
+    return null;
+  }
+  logger.debug('Found existing yarn.lock file');
+  const newYarnLock =
+    await getYarnLockFile(inputConfig.packageFile, packageContent, inputConfig.api);
+  logger.silly(`newYarnLock:\n${newYarnLock.contents}`);
+  if (existingYarnLock.toString() === newYarnLock.contents.toString()) {
+    logger.debug('Yarn lock file does not need updating');
+    return null;
+  }
+  logger.debug('Yarn lock needs updating');
+  return newYarnLock;
+}
+
 // Ensure branch exists with appropriate content
 async function ensureBranch(upgrades) {
   logger.debug(`ensureBranch(${JSON.stringify(upgrades)})`);
@@ -81,29 +104,38 @@ async function ensureBranch(upgrades) {
   const commitMessage = handlebars.compile(upgrades[0].commitMessage)(upgrades[0]);
   const api = upgrades[0].api;
   const packageFiles = {};
+  const commitFiles = [];
   for (const upgrade of upgrades) {
-    // See if this is the first time editing this file
-    if (!packageFiles[upgrade.packageFile]) {
-      // If we are rebasing then existing content will be from master
-      packageFiles[upgrade.packageFile] =
-        await api.getFileContent(upgrade.packageFile, parentBranch);
-    }
-    const newContent = packageJsonHelper.setNewValue(
-      packageFiles[upgrade.packageFile],
-      upgrade.depType,
-      upgrade.depName,
-      upgrade.newVersion);
-    if (packageFiles[upgrade.packageFile] === newContent) {
-      logger.debug('packageFile content unchanged');
-      delete packageFiles[upgrade.packageFile];
+    if (upgrade.upgradeType === 'maintainYarnLock') {
+      const newYarnLock = await maintainYarnLock(upgrade);
+      if (newYarnLock) {
+        commitFiles.push(newYarnLock);
+      }
     } else {
-      logger.debug('Updating packageFile content');
-      packageFiles[upgrade.packageFile] = newContent;
+      // See if this is the first time editing this file
+      if (!packageFiles[upgrade.packageFile]) {
+        // If we are rebasing then existing content will be from master
+        packageFiles[upgrade.packageFile] =
+          await api.getFileContent(upgrade.packageFile, parentBranch);
+      }
+      const newContent = packageJsonHelper.setNewValue(
+        packageFiles[upgrade.packageFile],
+        upgrade.depType,
+        upgrade.depName,
+        upgrade.newVersion);
+      if (packageFiles[upgrade.packageFile] === newContent) {
+        logger.debug('packageFile content unchanged');
+        delete packageFiles[upgrade.packageFile];
+      } else {
+        logger.debug('Updating packageFile content');
+        packageFiles[upgrade.packageFile] = newContent;
+      }
     }
   }
   if (Object.keys(packageFiles).length > 0) {
-    const commitFiles = [];
+    logger.debug(`${Object.keys(packageFiles).length} package file(s) need updating.`);
     for (const packageFile of Object.keys(packageFiles)) {
+      logger.debug(`Adding ${packageFile}`);
       commitFiles.push({
         name: packageFile,
         contents: packageFiles[packageFile],
@@ -112,11 +144,17 @@ async function ensureBranch(upgrades) {
         await module.exports.getYarnLockFile(packageFile, packageFiles[packageFile], api);
       if (yarnLockFile) {
         // Add new yarn.lock file too
+        logger.debug(`Adding ${yarnLockFile.name}`);
         commitFiles.push(yarnLockFile);
       }
     }
-
+  }
+  if (commitFiles.length) {
+    logger.debug(`Commit ${commitFiles.length} files to branch ${branchName}`);
     // API will know whether to create new branch or not
     await api.commitFilesToBranch(branchName, commitFiles, commitMessage, parentBranch);
+    return true;
   }
+  logger.debug(`No files to commit to branch ${branchName}`);
+  return false;
 }
diff --git a/readme.md b/readme.md
index 30bc5a2095335f29d534e5b6c1638e5a8c559fe8..24c48f4c4b30489712165bf902aeeb72d87a0adc 100644
--- a/readme.md
+++ b/readme.md
@@ -53,7 +53,7 @@ $ node renovate --help
     --respect-latest [boolean]           Ignore versions newer than npm "latest" version
     --recreate-closed [boolean]          Recreate PRs even if same ones were closed previously
     --rebase-stale-prs [boolean]         Rebase stale PRs (GitHub only)
-    --maintain-yarn-lock [boolean]       Keep yarn.lock updated in base branch (no monorepo support)
+    --maintain-yarn-lock [boolean]       Keep yarn.lock files updated in base branch
     --group-name <string>                Human understandable name for the dependency group
     --group-slug <string>                Slug to use for group (e.g. in branch name). Will be calculated from groupName if null
     --labels <list>                      Labels to add to Pull Request