diff --git a/docs/configuration.md b/docs/configuration.md
index f0f4a4f2ba8daa1e6362cfcd2549fcf84a45ffc9..9622839ea50384b7289e70a9aef2b501e13d076c 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -98,7 +98,6 @@ $ node renovate --help
     --automerge <string>                 What types of upgrades to merge to base branch automatically. Values: none, minor or any
     --automerge-type <string>            How to automerge - "branch-merge-commit", "branch-push" or "pr". Branch support is GitHub-only
     --yarn-cache-folder <string>         Location of yarn cache folder to use. Set to empty string to disable
-    --maintain-yarn-lock [boolean]       Keep yarn.lock files updated in base branch
     --lazy-grouping [boolean]            Use group names only when multiple dependencies upgraded
     --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
@@ -177,11 +176,14 @@ Obviously, you can't set repository or package file location with this method.
 | `prTitle` | Pull Request title template | string | `"{{semanticPrefix}}{{#if isPin}}Pin{{else}}Update{{/if}} dependency {{depName}} to version {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}{{newVersionMajor}}.x{{else}}{{newVersion}}{{/if}}{{/if}}"` | `RENOVATE_PR_TITLE` |  |
 | `prBody` | Pull Request body template | string | `"This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates dependency [{{depName}}]({{repositoryUrl}}) from version `{{currentVersion}}` to `{{newVersion}}`\n{{#if releases.length}}\n\n### Commits\n\n<details>\n<summary>{{githubName}}</summary>\n\n{{#each releases as |release|}}\n#### {{release.version}}\n{{#each release.commits as |commit|}}\n-   [`{{commit.shortSha}}`]({{commit.url}}) {{commit.message}}\n{{/each}}\n{{/each}}\n\n</details>\n{{/if}}\n<br />\n\nThis {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://keylocation.sg/our-tech/renovate)."` | `RENOVATE_PR_BODY` |  |
 | `yarnCacheFolder` | Location of yarn cache folder to use. Set to empty string to disable | string | `"/tmp/yarn-cache"` | `RENOVATE_YARN_CACHE_FOLDER` | `--yarn-cache-folder` |
-| `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"` | `RENOVATE_YARN_MAINTENANCE_BRANCH_NAME` |  |
-| `yarnMaintenanceCommitMessage` | Commit message template when maintaining yarn.lock | string | `"Renovate yarn.lock file"` | `RENOVATE_YARN_MAINTENANCE_COMMIT_MESSAGE` |  |
-| `yarnMaintenancePrTitle` | Pull Request title template when maintaining yarn.lock | string | `"Renovate yarn.lock file"` | `RENOVATE_YARN_MAINTENANCE_PR_TITLE` |  |
-| `yarnMaintenancePrBody` | Pull Request body template when maintaining yarn.lock | string | `"This PR regenerates yarn.lock files based on the existing `package.json` files."` | `RENOVATE_YARN_MAINTENANCE_PR_BODY` |  |
+| `lockFileMaintenance` | Configuration for lock file maintenance | json | `{
+  "enabled": true,
+  "branchName": "renovate/lock-files",
+  "commitMessage": "{{semanticPrefix}}Update lock file",
+  "prTitle": "{{semanticPrefix}}Lock file maintenance",
+  "prBody": "This PR regenerates lock files to keep them up-to-date.",
+  "schedule": "before 5am on monday"
+}` |  |  |
 | `lazyGrouping` | Use group names only when multiple dependencies upgraded | boolean | `true` | `RENOVATE_LAZY_GROUPING` | `--lazy-grouping` |
 | `groupName` | Human understandable name for the dependency group | string | `null` | `RENOVATE_GROUP_NAME` | `--group-name` |
 | `groupSlug` | Slug to use for group (e.g. in branch name). Will be calculated from groupName if null | string | `null` | `RENOVATE_GROUP_SLUG` | `--group-slug` |
diff --git a/docs/faq.md b/docs/faq.md
index 3236238549f6ba3697f8445054c0fca78a62ca01..eb4cde9af702a66a76c3271b3429170470931777 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -85,7 +85,7 @@ Set configuration option `pinVersions` to `false`.
 
 ### Keep `yarn.lock` sub-dependencies up-to-date, even when `package.json` hasn't changed
 
-Set configuration option `maintainYarnLock` to `true`.
+This is enabled by default, but its schedule is set to 'before 5am on monday'. If you want it more frequently, then update the `schedule` field inside the `lockFileMaintenance` object.
 
 ### Wait until tests have passed before creating the PR
 
diff --git a/lib/config/defaults.js b/lib/config/defaults.js
index 171a08f25d11b2c5c3e03c0e523e48bc2ab7f2de..1af5ad9202313119c9f24da207ad74bd9ac4a55d 100644
--- a/lib/config/defaults.js
+++ b/lib/config/defaults.js
@@ -9,6 +9,7 @@ const defaultValues = {
   boolean: true,
   list: [],
   string: null,
+  json: null,
 };
 
 function getDefault(option) {
diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index ed7f2f7b56bf5a48cf61b7a09e8b8c6ec9e2cbb4..b7f676e8dfd779935951f83c62329eb0aca0d3c2 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -256,48 +256,22 @@ const options = [
     default: '/tmp/yarn-cache',
   },
   {
-    name: 'maintainYarnLock',
-    description: 'Keep yarn.lock files updated in base branch',
+    name: 'lockFileMaintenance',
+    description: 'Configuration for lock file maintenance',
     level: 'packageFile',
-    type: 'boolean',
-    default: false,
-  },
-  {
-    name: 'yarnMaintenanceBranchName',
-    description: 'Branch name template when maintaining yarn.lock',
-    level: 'packageFile',
-    type: 'string',
-    default: 'renovate/yarn-lock',
-    cli: false,
-    onboarding: false,
-  },
-  {
-    name: 'yarnMaintenanceCommitMessage',
-    description: 'Commit message template when maintaining yarn.lock',
-    level: 'packageFile',
-    type: 'string',
-    default: 'Renovate yarn.lock file',
-    cli: false,
-    onboarding: false,
-  },
-  {
-    name: 'yarnMaintenancePrTitle',
-    description: 'Pull Request title template when maintaining yarn.lock',
-    level: 'packageFile',
-    type: 'string',
-    default: 'Renovate yarn.lock file',
-    cli: false,
-    onboarding: false,
-  },
-  {
-    name: 'yarnMaintenancePrBody',
-    description: 'Pull Request body template when maintaining yarn.lock',
-    level: 'packageFile',
-    type: 'string',
-    default:
-      'This PR regenerates yarn.lock files based on the existing `package.json` files.',
+    type: 'json',
+    default: {
+      enabled: true,
+      branchName: 'renovate/lock-files',
+      commitMessage: '{{semanticPrefix}}Update lock file',
+      prTitle: '{{semanticPrefix}}Lock file maintenance',
+      prBody: 'This PR regenerates lock files to keep them up-to-date.',
+      schedule: 'before 5am on monday',
+    },
     cli: false,
+    env: false,
     onboarding: false,
+    mergeable: true,
   },
   // Dependency Groups
   {
diff --git a/lib/config/index.js b/lib/config/index.js
index 877f7cb9803ba7b6fd7d7184aa7b85b8f536e19a..aeb7a94d686006d4a5413cb44289ecd68924bd82 100644
--- a/lib/config/index.js
+++ b/lib/config/index.js
@@ -13,6 +13,7 @@ const githubApp = require('./github-app');
 
 module.exports = {
   parseConfigs,
+  mergeChildConfig,
   filterConfig,
   getOnboardingConfig,
 };
@@ -117,6 +118,25 @@ async function parseConfigs(env, argv) {
   return config;
 }
 
+function mergeChildConfig(parentConfig, childConfig) {
+  const config = Object.assign({}, parentConfig, childConfig);
+  for (const option of definitions.getOptions()) {
+    if (option.mergeable && childConfig[option.name]) {
+      logger.debug(`mergeable option: ${option.name}`);
+      // TODO: handle arrays
+      config[option.name] = Object.assign(
+        {},
+        parentConfig[option.name],
+        childConfig[option.name]
+      );
+      logger.debug(
+        `config.${option.name}=${JSON.stringify(config[option.name])}`
+      );
+    }
+  }
+  return config;
+}
+
 function filterConfig(inputConfig, filterLevel) {
   const outputConfig = Object.assign({}, inputConfig);
   const levelScores = {
diff --git a/lib/workers/branch/index.js b/lib/workers/branch/index.js
index 164e2bcf441d895a45e1177e78bdd1525f24b678..11880291fc160b9a7f4854f6ab02f0eb5cdadba0 100644
--- a/lib/workers/branch/index.js
+++ b/lib/workers/branch/index.js
@@ -78,7 +78,8 @@ async function ensureBranch(upgrades) {
   const packageFiles = {};
   const commitFiles = [];
   for (const upgrade of upgrades) {
-    if (upgrade.upgradeType === 'maintainYarnLock') {
+    if (upgrade.upgradeType === 'lockFileMaintenance') {
+      logger.debug('branch lockFileMaintenance');
       try {
         const newYarnLock = await yarn.maintainLockFile(upgrade);
         if (newYarnLock) {
@@ -220,7 +221,7 @@ async function updateBranch(upgrades) {
 
   try {
     if (
-      upgrade0.upgradeType !== 'maintainYarnLock' &&
+      upgrade0.upgradeType !== 'lockFileMaintenance' &&
       upgrade0.groupName === null &&
       !upgrade0.recreateClosed &&
       (await upgrade0.api.checkForClosedPr(branchName, prTitle))
@@ -243,19 +244,23 @@ async function updateBranch(upgrades) {
 }
 
 async function removeStandaloneBranches(upgrades) {
-  if (upgrades.length > 1) {
-    for (const upgrade of upgrades) {
-      const standaloneBranchName = handlebars.compile(upgrade.branchName)(
-        upgrade
-      );
-      upgrade.logger.debug(`Need to delete branch ${standaloneBranchName}`);
-      try {
-        await upgrade.api.deleteBranch(standaloneBranchName);
-      } catch (err) {
-        upgrade.logger.debug(`Couldn't delete branch ${standaloneBranchName}`);
-      }
-      // Rename to group branchName
-      upgrade.branchName = upgrade.groupBranchName;
+  if (upgrades.length <= 1) {
+    return;
+  }
+  if (upgrades[0].upgradeType === 'lockFileMaintenance') {
+    return;
+  }
+  for (const upgrade of upgrades) {
+    const standaloneBranchName = handlebars.compile(upgrade.branchName)(
+      upgrade
+    );
+    upgrade.logger.debug(`Need to delete branch ${standaloneBranchName}`);
+    try {
+      await upgrade.api.deleteBranch(standaloneBranchName);
+    } catch (err) {
+      upgrade.logger.debug(`Couldn't delete branch ${standaloneBranchName}`);
     }
+    // Rename to group branchName
+    upgrade.branchName = upgrade.groupBranchName;
   }
 }
diff --git a/lib/workers/branch/yarn.js b/lib/workers/branch/yarn.js
index 7453f38066cb3e18f8842e415a4c49a0a0f623b6..82a675cb6f939bb59bac9b4821fa1fc26627a117 100644
--- a/lib/workers/branch/yarn.js
+++ b/lib/workers/branch/yarn.js
@@ -89,7 +89,7 @@ async function getLockFile(
 }
 
 async function maintainLockFile(inputConfig) {
-  logger.debug(`maintainYarnLock(${JSON.stringify(inputConfig)})`);
+  logger.debug(`maintainLockFile(${JSON.stringify(inputConfig)})`);
   const packageContent = await inputConfig.api.getFileContent(
     inputConfig.packageFile
   );
diff --git a/lib/workers/dep-type/index.js b/lib/workers/dep-type/index.js
index 5545a45f59f8e1c54b50da7841695ede966c5a50..4075e25097e00c0449c68e6c2da9771473bebce9 100644
--- a/lib/workers/dep-type/index.js
+++ b/lib/workers/dep-type/index.js
@@ -50,7 +50,7 @@ async function findUpgrades(packageContent, config) {
 }
 
 function getDepConfig(depTypeConfig, dep) {
-  const depConfig = Object.assign({}, depTypeConfig, dep);
+  const depConfig = configParser.mergeChildConfig(depTypeConfig, dep);
   // Apply any matching package rules
   if (depConfig.packages) {
     let packageRuleApplied = false;
diff --git a/lib/workers/global/index.js b/lib/workers/global/index.js
index ed8060745003733cfb8aff651bb3896d167fc3bc..2417d1a297e6961bf4b8b4bfb8526ff0794101e2 100644
--- a/lib/workers/global/index.js
+++ b/lib/workers/global/index.js
@@ -32,7 +32,7 @@ function getRepositoryConfig(globalConfig, index) {
   if (typeof repository === 'string') {
     repository = { repository };
   }
-  const repoConfig = Object.assign({}, globalConfig, repository);
+  const repoConfig = configParser.mergeChildConfig(globalConfig, repository);
   repoConfig.logger = logger.child({
     repository: repoConfig.repository,
   });
diff --git a/lib/workers/package-file/index.js b/lib/workers/package-file/index.js
index c45a3ff71e3df8ee94c5d34aef42635dcc919c9f..eac9bdd0d50eeaf65bb7ea0fddefe182c0edaa77 100644
--- a/lib/workers/package-file/index.js
+++ b/lib/workers/package-file/index.js
@@ -1,5 +1,7 @@
 const configParser = require('../../config');
 const depTypeWorker = require('../dep-type');
+const schedule = require('../package/schedule');
+
 let logger = require('../../logger');
 
 module.exports = {
@@ -7,7 +9,8 @@ module.exports = {
   getDepTypeConfig,
 };
 
-async function findUpgrades(config) {
+async function findUpgrades(packageFileConfig) {
+  let config = Object.assign({}, packageFileConfig);
   logger = config.logger || logger;
   logger.info(`Processing package file`);
   // If onboarding, use the package.json in onboarding branch
@@ -29,7 +32,7 @@ async function findUpgrades(config) {
       'package.json>renovate config'
     );
     // package.json>renovate config takes precedence over existing config
-    Object.assign(config, packageContent.renovate);
+    config = configParser.mergeChildConfig(config, packageContent.renovate);
   } else {
     logger.debug('Package file has no renovate configuration');
   }
@@ -50,24 +53,31 @@ async function findUpgrades(config) {
     );
   }
 
-  if (config.maintainYarnLock) {
-    const upgrade = Object.assign({}, config, {
-      upgradeType: 'maintainYarnLock',
-    });
-    upgrade.upgradeType = 'maintainYarnLock';
-    upgrade.commitMessage = upgrade.yarnMaintenanceCommitMessage;
-    upgrade.branchName = upgrade.yarnMaintenanceBranchName;
-    upgrade.prTitle = upgrade.yarnMaintenancePrTitle;
-    upgrade.prBody = upgrade.yarnMaintenancePrBody;
-    upgrades.push(upgrade);
+  // Maintain lock files
+  const lockFileMaintenanceConf = Object.assign(
+    {},
+    config,
+    config.lockFileMaintenance
+  );
+  if (lockFileMaintenanceConf.enabled) {
+    logger.debug('lockFileMaintenance enabled');
+    lockFileMaintenanceConf.upgradeType = 'lockFileMaintenance';
+    if (schedule.isScheduledNow(lockFileMaintenanceConf)) {
+      logger.debug(`lock config=${JSON.stringify(lockFileMaintenanceConf)}`);
+      upgrades.push(lockFileMaintenanceConf);
+    }
   }
+
   logger.info('Finished processing package file');
   return upgrades;
 }
 
 function getDepTypeConfig(packageFileConfig, depType) {
   let depTypeConfig = typeof depType === 'string' ? { depType } : depType;
-  depTypeConfig = Object.assign({}, packageFileConfig, depTypeConfig);
+  depTypeConfig = configParser.mergeChildConfig(
+    packageFileConfig,
+    depTypeConfig
+  );
   depTypeConfig.logger = logger.child({
     repository: depTypeConfig.repository,
     packageFile: depTypeConfig.packageFile,
diff --git a/lib/workers/package/index.js b/lib/workers/package/index.js
index 388ef1c27d905817e900f4402ee97e567d95f938..46cc391fc722a8d11af009a35120eb53d7297889 100644
--- a/lib/workers/package/index.js
+++ b/lib/workers/package/index.js
@@ -16,7 +16,7 @@ async function findUpgrades(config) {
     return [];
   }
   // Check schedule
-  if (config.schedule && !schedule.isPackageScheduled(config)) {
+  if (config.schedule && !schedule.isScheduledNow(config)) {
     logger.debug('Skipping package as it is not scheduled');
     return [];
   }
diff --git a/lib/workers/package/schedule.js b/lib/workers/package/schedule.js
index 5cc678dac7ab11a421d53872b24f99985c90200b..fd00ed749c19454b654769106252007b17ce4881 100644
--- a/lib/workers/package/schedule.js
+++ b/lib/workers/package/schedule.js
@@ -3,7 +3,7 @@ const moment = require('moment-timezone');
 
 module.exports = {
   hasValidSchedule,
-  isPackageScheduled,
+  isScheduledNow,
 };
 
 function fixShortHours(input) {
@@ -45,7 +45,7 @@ function hasValidSchedule(schedule, logger) {
   return true;
 }
 
-function isPackageScheduled(config) {
+function isScheduledNow(config) {
   config.logger.debug(`Checking schedule ${JSON.stringify(config.schedule)}`);
   // Massage into array
   const configSchedule =
diff --git a/lib/workers/repository/upgrades.js b/lib/workers/repository/upgrades.js
index cc8cf4a752080b03f18b22f4561187791c5508c6..74c4474585c16feb99bec21e10a766fff9f631f1 100644
--- a/lib/workers/repository/upgrades.js
+++ b/lib/workers/repository/upgrades.js
@@ -64,7 +64,10 @@ function getPackageFileConfig(repoConfig, index) {
   if (typeof packageFile === 'string') {
     packageFile = { packageFile };
   }
-  const packageFileConfig = Object.assign({}, repoConfig, packageFile);
+  const packageFileConfig = configParser.mergeChildConfig(
+    repoConfig,
+    packageFile
+  );
   repoConfig.logger.trace({ config: repoConfig }, 'repoConfig');
   packageFileConfig.logger = packageFileConfig.logger.child({
     repository: packageFileConfig.repository,
diff --git a/test/config/__snapshots__/index.spec.js.snap b/test/config/__snapshots__/index.spec.js.snap
new file mode 100644
index 0000000000000000000000000000000000000000..6d3c38b5e10ea4e232ce7a54f3c46cce14bdfd94
--- /dev/null
+++ b/test/config/__snapshots__/index.spec.js.snap
@@ -0,0 +1,12 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`config/index mergeChildConfig(parentConfig, childConfig) merges 1`] = `
+Object {
+  "branchName": "renovate/lock-files",
+  "commitMessage": "{{semanticPrefix}}Update lock file",
+  "enabled": true,
+  "prBody": "This PR regenerates lock files to keep them up-to-date.",
+  "prTitle": "{{semanticPrefix}}Lock file maintenance",
+  "schedule": "on monday",
+}
+`;
diff --git a/test/config/index.spec.js b/test/config/index.spec.js
index b63b46addccb302c671fa07c25288362b8eb6942..b554d503b0cb5796eb8c2871126dd59f2e2961d7 100644
--- a/test/config/index.spec.js
+++ b/test/config/index.spec.js
@@ -1,4 +1,5 @@
 const argv = require('../_fixtures/config/argv');
+const defaultConfig = require('../../lib/config/defaults').getConfig();
 
 describe('config/index', () => {
   describe('.parseConfigs(env, defaultArgv)', () => {
@@ -160,4 +161,22 @@ describe('config/index', () => {
       expect(glGot.mock.calls.length).toBe(0);
     });
   });
+  describe('mergeChildConfig(parentConfig, childConfig)', () => {
+    it('merges', () => {
+      const parentConfig = Object.assign({}, defaultConfig);
+      const childConfig = {
+        foo: 'bar',
+        pinVersions: false,
+        lockFileMaintenance: {
+          schedule: 'on monday',
+        },
+      };
+      const configParser = require('../../lib/config/index.js');
+      const config = configParser.mergeChildConfig(parentConfig, childConfig);
+      expect(config.foo).toEqual('bar');
+      expect(config.pinVersions).toBe(false);
+      expect(config.lockFileMaintenance.schedule).toEqual('on monday');
+      expect(config.lockFileMaintenance).toMatchSnapshot();
+    });
+  });
 });
diff --git a/test/workers/branch/index.spec.js b/test/workers/branch/index.spec.js
index a5973923bf16fc98ca8a640e2f50af1a700de8f4..00151d58bc528924b55025addbc7185ba8115e80 100644
--- a/test/workers/branch/index.spec.js
+++ b/test/workers/branch/index.spec.js
@@ -279,7 +279,7 @@ describe('workers/branch', () => {
     it('maintains lock files if needing updates', async () => {
       branchWorker.getParentBranch.mockReturnValueOnce('dummy branch');
       yarn.maintainLockFile.mockReturnValueOnce('non null response');
-      config.upgradeType = 'maintainYarnLock';
+      config.upgradeType = 'lockFileMaintenance';
       await branchWorker.ensureBranch([config]);
       expect(branchWorker.getParentBranch.mock.calls.length).toBe(1);
       expect(packageJsonHelper.setNewValue.mock.calls.length).toBe(0);
@@ -290,7 +290,7 @@ describe('workers/branch', () => {
     });
     it('skips maintaining lock files if no updates', async () => {
       branchWorker.getParentBranch.mockReturnValueOnce('dummy branch');
-      config.upgradeType = 'maintainYarnLock';
+      config.upgradeType = 'lockFileMaintenance';
       await branchWorker.ensureBranch([config]);
       expect(branchWorker.getParentBranch.mock.calls.length).toBe(1);
       expect(packageJsonHelper.setNewValue.mock.calls.length).toBe(0);
@@ -301,7 +301,7 @@ describe('workers/branch', () => {
     });
     it('throws error if cannot maintain yarn.lock file', async () => {
       branchWorker.getParentBranch.mockReturnValueOnce('dummy branch');
-      config.upgradeType = 'maintainYarnLock';
+      config.upgradeType = 'lockFileMaintenance';
       yarn.maintainLockFile.mockImplementationOnce(() => {
         throw new Error('yarn not found');
       });
@@ -372,6 +372,14 @@ describe('workers/branch', () => {
     });
   });
   describe('removeStandaloneBranches(upgrades)', () => {
+    it('returns if length is one or less', async () => {
+      const upgrades = [{}];
+      await branchWorker.removeStandaloneBranches(upgrades);
+    });
+    it('returns if upgradeType is lockFileMaintenance', async () => {
+      const upgrades = [{ upgradeType: 'lockFileMaintenance' }, {}];
+      await branchWorker.removeStandaloneBranches(upgrades);
+    });
     it('deletes standalone branch names', async () => {
       const api = {
         deleteBranch: jest.fn(),
diff --git a/test/workers/package-file/index.spec.js b/test/workers/package-file/index.spec.js
index 7ebbba144b5527bf5d8d84694e40a8b6d0d3961e..238785d6ffc596840627f679ad4a95413141dbe0 100644
--- a/test/workers/package-file/index.spec.js
+++ b/test/workers/package-file/index.spec.js
@@ -1,19 +1,25 @@
 const packageFileWorker = require('../../../lib/workers/package-file');
 const depTypeWorker = require('../../../lib/workers/dep-type');
+const schedule = require('../../../lib/workers/package/schedule');
+const defaultConfig = require('../../../lib/config/defaults').getConfig();
+
+const logger = require('../../_fixtures/logger');
 
 jest.mock('../../../lib/workers/dep-type');
+jest.mock('../../../lib/workers/package/schedule');
 
 describe('packageFileWorker', () => {
   describe('findUpgrades(config)', () => {
     let config;
     beforeEach(() => {
-      config = {
+      config = Object.assign({}, defaultConfig, {
         repoIsOnboarded: true,
         api: {
           getFileJson: jest.fn(),
         },
         depTypes: ['dependencies', 'devDependencies'],
-      };
+        logger,
+      });
       packageFileWorker.updateBranch = jest.fn();
     });
     it('handles null', async () => {
@@ -55,10 +61,17 @@ describe('packageFileWorker', () => {
     });
     it('maintains yarn.lock', async () => {
       config.api.getFileJson.mockReturnValueOnce({});
-      config.maintainYarnLock = true;
       depTypeWorker.findUpgrades.mockReturnValue([]);
+      schedule.isScheduledNow.mockReturnValueOnce(true);
       const res = await packageFileWorker.findUpgrades(config);
       expect(res).toHaveLength(1);
     });
+    it('skips yarn.lock', async () => {
+      config.api.getFileJson.mockReturnValueOnce({});
+      depTypeWorker.findUpgrades.mockReturnValue([]);
+      schedule.isScheduledNow.mockReturnValueOnce(false);
+      const res = await packageFileWorker.findUpgrades(config);
+      expect(res).toHaveLength(0);
+    });
   });
 });
diff --git a/test/workers/package/index.spec.js b/test/workers/package/index.spec.js
index 4ab6054f5dd3b5b28d56780b7108e1bcd5c81bb6..67a933412c2e58ca353d5ff80be0c17ac33a54fb 100644
--- a/test/workers/package/index.spec.js
+++ b/test/workers/package/index.spec.js
@@ -22,14 +22,14 @@ describe('lib/workers/package/index', () => {
     });
     it('returns empty if package is not scheduled', async () => {
       config.schedule = 'some schedule';
-      schedule.isPackageScheduled.mockReturnValueOnce(false);
+      schedule.isScheduledNow.mockReturnValueOnce(false);
       const res = await pkgWorker.findUpgrades(config);
       expect(res).toMatchObject([]);
       expect(npmApi.getDependency.mock.calls.length).toBe(0);
     });
     it('returns empty if no npm dep found', async () => {
       config.schedule = 'some schedule';
-      schedule.isPackageScheduled.mockReturnValueOnce(true);
+      schedule.isScheduledNow.mockReturnValueOnce(true);
       const res = await pkgWorker.findUpgrades(config);
       expect(res).toMatchObject([]);
       expect(npmApi.getDependency.mock.calls.length).toBe(1);
diff --git a/test/workers/package/schedule.spec.js b/test/workers/package/schedule.spec.js
index 477d143e5f1873ec006be7663df077c1506db25d..1e09b482d29a9cded251ec75cac8c66e7a400e56 100644
--- a/test/workers/package/schedule.spec.js
+++ b/test/workers/package/schedule.spec.js
@@ -73,7 +73,7 @@ describe('workers/package/schedule', () => {
       expect(res).toBe(true);
     });
   });
-  describe('isPackageScheduled(config)', () => {
+  describe('isScheduledNow(config)', () => {
     let config;
     beforeEach(() => {
       mockDate.set(1498812608678); // 2017-06-30 10:50am
@@ -83,43 +83,43 @@ describe('workers/package/schedule', () => {
       };
     });
     it('returns true if no schedule', () => {
-      const res = schedule.isPackageScheduled(config);
+      const res = schedule.isScheduledNow(config);
       expect(res).toBe(true);
     });
     it('supports before hours true', () => {
       config.schedule = 'before 4:00pm';
-      const res = schedule.isPackageScheduled(config);
+      const res = schedule.isScheduledNow(config);
       expect(res).toBe(true);
     });
     it('supports before hours false', () => {
       config.schedule = 'before 4:00am';
-      const res = schedule.isPackageScheduled(config);
+      const res = schedule.isScheduledNow(config);
       expect(res).toBe(false);
     });
     it('supports outside hours', () => {
       config.schedule = 'after 4:00pm';
-      const res = schedule.isPackageScheduled(config);
+      const res = schedule.isScheduledNow(config);
       expect(res).toBe(false);
     });
     it('supports timezone', () => {
       config.schedule = 'after 4:00pm';
       config.timezone = 'Asia/Singapore';
-      const res = schedule.isPackageScheduled(config);
+      const res = schedule.isScheduledNow(config);
       expect(res).toBe(true);
     });
     it('supports multiple schedules', () => {
       config.schedule = ['after 4:00pm', 'before 11:00am'];
-      const res = schedule.isPackageScheduled(config);
+      const res = schedule.isScheduledNow(config);
       expect(res).toBe(true);
     });
     it('supports day match', () => {
       config.schedule = 'on friday and saturday';
-      const res = schedule.isPackageScheduled(config);
+      const res = schedule.isScheduledNow(config);
       expect(res).toBe(true);
     });
     it('supports day mismatch', () => {
       config.schedule = 'on monday and tuesday';
-      const res = schedule.isPackageScheduled(config);
+      const res = schedule.isScheduledNow(config);
       expect(res).toBe(false);
     });
   });
diff --git a/test/workers/repository/__snapshots__/onboarding.spec.js.snap b/test/workers/repository/__snapshots__/onboarding.spec.js.snap
index eb34f043e32f2513db510ebf98dc67555e1f6c50..59d42f5eba7adf7239d75e0222d22b1cf24645a6 100644
--- a/test/workers/repository/__snapshots__/onboarding.spec.js.snap
+++ b/test/workers/repository/__snapshots__/onboarding.spec.js.snap
@@ -96,7 +96,6 @@ Array [
   \\"automerge\\": \\"none\\",
   \\"branchName\\": \\"renovate/{{depName}}-{{newVersionMajor}}.x\\",
   \\"commitMessage\\": \\"{{semanticPrefix}}Update dependency {{depName}} to version {{newVersion}}\\",
-  \\"maintainYarnLock\\": false,
   \\"labels\\": [],
   \\"assignees\\": [],
   \\"reviewers\\": []