diff --git a/lib/config/definitions.js b/lib/config/definitions.js
index 069eece75a5de2491f9342ee0b4c9e01c74ca61c..4b9dc1ff5feeba46ecd2fb3843cea6c705d2867d 100644
--- a/lib/config/definitions.js
+++ b/lib/config/definitions.js
@@ -1080,10 +1080,15 @@ const options = [
   {
     name: 'postUpdateOptions',
     description:
-      'Enable various post-update options to be run after package/artifact updating',
+      'Enable post-update options to be run after package/artifact updating',
     type: 'list',
     default: [],
-    allowedValues: ['gomodTidy'],
+    allowedValues: [
+      'gomodTidy',
+      'npmDedupe',
+      'yarnDedupeFewer',
+      'yarnDedupeHighest',
+    ],
     cli: false,
     env: false,
     mergeable: true,
diff --git a/lib/manager/npm/post-update/index.js b/lib/manager/npm/post-update/index.js
index e26868e8b1c86723e1c0971c2f58f4a4b1fe40b8..720f235b2f715c817c8b0465c911a9ba32b77b02 100644
--- a/lib/manager/npm/post-update/index.js
+++ b/lib/manager/npm/post-update/index.js
@@ -378,8 +378,7 @@ async function getAdditionalFiles(config, packageFiles) {
       upath.join(config.localDir, lockFileDir),
       env,
       fileName,
-      config.skipInstalls,
-      config.binarySource,
+      config,
       upgrades
     );
     if (res.error) {
diff --git a/lib/manager/npm/post-update/npm.js b/lib/manager/npm/post-update/npm.js
index 4469042a4ddf6771b3b1ef3c26ec648bc56100bf..9c6dc96d0691298c1f6369002d9fa7bc26a0dfc3 100644
--- a/lib/manager/npm/post-update/npm.js
+++ b/lib/manager/npm/post-update/npm.js
@@ -11,15 +11,16 @@ async function generateLockFile(
   cwd,
   env,
   filename,
-  skipInstalls,
-  binarySource,
+  config = {},
   upgrades = []
 ) {
   logger.debug(`Spawning npm install to create ${cwd}/${filename}`);
+  const { skipInstalls, binarySource, postUpdateOptions } = config;
   let lockFile = null;
   let stdout;
   let stderr;
   let cmd;
+  let args = '';
   try {
     const startTime = process.hrtime();
     try {
@@ -62,15 +63,15 @@ async function generateLockFile(
     if (binarySource === 'global') {
       cmd = 'npm';
     }
-    cmd = `${cmd} --version && ${cmd} install`;
+    args = `install`;
     if (skipInstalls) {
-      cmd += ' --package-lock-only --no-audit';
+      args += ' --package-lock-only --no-audit';
     } else {
-      cmd += ' --ignore-scripts --no-audit';
+      args += ' --ignore-scripts --no-audit';
     }
-    logger.debug(`Using npm: ${cmd}`);
+    logger.debug(`Using npm: ${cmd} ${args}`);
     // TODO: Switch to native util.promisify once using only node 8
-    ({ stdout, stderr } = await exec(cmd, {
+    ({ stdout, stderr } = await exec(`${cmd} ${args}`, {
       cwd,
       shell: true,
       env,
@@ -81,15 +82,27 @@ async function generateLockFile(
     if (lockUpdates.length) {
       logger.info('Performing lockfileUpdate (npm)');
       const updateCmd =
-        cmd +
+        `${cmd} ${args}` +
         lockUpdates
           .map(update => ` ${update.depName}@${update.toVersion}`)
           .join('');
-      ({ stdout, stderr } = await exec(updateCmd, {
+      const updateRes = await exec(updateCmd, {
         cwd,
         shell: true,
         env,
-      }));
+      });
+      stdout += updateRes.stdout ? updateRes.stdout : '';
+      stderr += updateRes.stderr ? updateRes.stderr : '';
+    }
+    if (postUpdateOptions && postUpdateOptions.includes('npmDedupe')) {
+      logger.info('Performing npm dedupe');
+      const dedupeRes = await exec(`${cmd} dedupe`, {
+        cwd,
+        shell: true,
+        env,
+      });
+      stdout += dedupeRes.stdout ? dedupeRes.stdout : '';
+      stderr += dedupeRes.stderr ? dedupeRes.stderr : '';
     }
     const duration = process.hrtime(startTime);
     const seconds = Math.round(duration[0] + duration[1] / 1e9);
@@ -102,6 +115,7 @@ async function generateLockFile(
     logger.info(
       {
         cmd,
+        args,
         err,
         stdout,
         stderr,
diff --git a/lib/manager/npm/post-update/yarn.js b/lib/manager/npm/post-update/yarn.js
index 821cad6fdffdf91fb1383ea58eb819d9a4a4151e..361a3ab9ec3444b1dd87a8ca5a5b4d5f5b6b5b10 100644
--- a/lib/manager/npm/post-update/yarn.js
+++ b/lib/manager/npm/post-update/yarn.js
@@ -101,11 +101,41 @@ async function generateLockFile(cwd, env, config = {}, upgrades = []) {
         ' upgrade' +
         lockUpdates.map(depName => ` ${depName}`).join('') +
         cmdExtras;
-      ({ stdout, stderr } = await exec(updateCmd, {
+      const updateRes = await exec(updateCmd, {
         cwd,
         shell: true,
         env,
-      }));
+      });
+      stdout += updateRes.stdout ? updateRes.stdout : '';
+      stderr += updateRes.stderr ? updateRes.stderr : '';
+    }
+    if (
+      config.postUpdateOptions &&
+      config.postUpdateOptions.includes('yarnDedupeFewer')
+    ) {
+      logger.info('Performing yarn dedupe fewer');
+      const dedupeCommand = 'npx yarn-deduplicate@1.1.1 --strategy fewer';
+      const dedupeRes = await exec(dedupeCommand, {
+        cwd,
+        shell: true,
+        env,
+      });
+      stdout += dedupeRes.stdout ? dedupeRes.stdout : '';
+      stderr += dedupeRes.stderr ? dedupeRes.stderr : '';
+    }
+    if (
+      config.postUpdateOptions &&
+      config.postUpdateOptions.includes('yarnDedupeHighest')
+    ) {
+      logger.info('Performing yarn dedupe highest');
+      const dedupeCommand = 'npx yarn-deduplicate@1.1.1 --strategy highest';
+      const dedupeRes = await exec(dedupeCommand, {
+        cwd,
+        shell: true,
+        env,
+      });
+      stdout += dedupeRes.stdout ? dedupeRes.stdout : '';
+      stderr += dedupeRes.stderr ? dedupeRes.stderr : '';
     }
     const duration = process.hrtime(startTime);
     const seconds = Math.round(duration[0] + duration[1] / 1e9);
diff --git a/test/workers/branch/lock-files/npm.spec.js b/test/workers/branch/lock-files/npm.spec.js
index 1e36155ff5b926d555e4a4b743c28c5c197dadac..404e3679bb745f9e84e53ec97ca280a6290ec604 100644
--- a/test/workers/branch/lock-files/npm.spec.js
+++ b/test/workers/branch/lock-files/npm.spec.js
@@ -17,13 +17,18 @@ describe('generateLockFile', () => {
       stdout: '',
       stderror: '',
     });
+    exec.mockReturnValueOnce({
+      stdout: '',
+      stderror: '',
+    });
     fs.readFile = jest.fn(() => 'package-lock-contents');
     const skipInstalls = true;
+    const postUpdateOptions = ['npmDedupe'];
     const res = await npmHelper.generateLockFile(
       'some-dir',
       {},
       'package-lock.json',
-      skipInstalls
+      { skipInstalls, postUpdateOptions }
     );
     expect(fs.readFile.mock.calls.length).toEqual(1);
     expect(res.error).not.toBeDefined();
@@ -48,8 +53,7 @@ describe('generateLockFile', () => {
       'some-dir',
       {},
       'package-lock.json',
-      skipInstalls,
-      null,
+      { skipInstalls },
       updates
     );
     expect(fs.readFile.mock.calls.length).toEqual(1);
@@ -69,8 +73,7 @@ describe('generateLockFile', () => {
       'some-dir',
       {},
       'package-lock.json',
-      skipInstalls,
-      binarySource
+      { skipInstalls, binarySource }
     );
     expect(fs.readFile.mock.calls.length).toEqual(1);
     expect(res.error).not.toBeDefined();
diff --git a/test/workers/branch/lock-files/yarn.spec.js b/test/workers/branch/lock-files/yarn.spec.js
index a583500ff0ea38cf0a0d2e777a45b4d43de7093b..69f41b89f46ff7050385485834500b5b217f6d1d 100644
--- a/test/workers/branch/lock-files/yarn.spec.js
+++ b/test/workers/branch/lock-files/yarn.spec.js
@@ -17,8 +17,20 @@ describe('generateLockFile', () => {
       stdout: '',
       stderror: '',
     });
+    exec.mockReturnValueOnce({
+      stdout: '',
+      stderror: '',
+    });
+    exec.mockReturnValueOnce({
+      stdout: '',
+      stderror: '',
+    });
     fs.readFile = jest.fn(() => 'package-lock-contents');
-    const res = await yarnHelper.generateLockFile('some-dir');
+    const env = {};
+    const config = {
+      postUpdateOptions: ['yarnDedupeFewer', 'yarnDedupeHighest'],
+    };
+    const res = await yarnHelper.generateLockFile('some-dir', env, config);
     expect(fs.readFile.mock.calls.length).toEqual(1);
     expect(res.lockFile).toEqual('package-lock-contents');
   });
diff --git a/website/docs/configuration-options.md b/website/docs/configuration-options.md
index a8400bb730816c7b1f41708b3549534d842ef0e0..601416e335cb4c47ac5932284ef10c6246a4490c 100644
--- a/website/docs/configuration-options.md
+++ b/website/docs/configuration-options.md
@@ -670,7 +670,10 @@ Warning: 'pipenv' support is currently in beta, so it is not enabled by default.
 
 ## postUpdateOptions
 
-`gomodTidy`: Enable to run `go mod tidy` after Go module updates
+`gomodTidy`: Run `go mod tidy` after Go module updates
+`npmDedupe`: Run `npm dedupe` after `package-lock.json` updates
+`yarnDedupeFewer`: Run `yarn-deduplicate --strategy fewer` after `yarn.lock` updates
+`yarnDedupeHighest`: Run `yarn-deduplicate --strategy highest` after `yarn.lock` updates
 
 ## prBodyColumns