diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index 51a02f3db66b23a89b218ed2fab564328e2baef4..e1ee7b04372b42f760c0685ad0fd62faa91b82c5 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -2972,7 +2972,7 @@ Table with options:
 | `gomodTidyE`                 | Run `go mod tidy -e` after Go module updates.                                                                                                              |
 | `gomodUpdateImportPaths`     | Update source import paths on major module updates, using [mod](https://github.com/marwan-at-work/mod).                                                    |
 | `helmUpdateSubChartArchives` | Update subchart archives in the `/charts` folder.                                                                                                          |
-| `npmDedupe`                  | Run `npm dedupe` after `package-lock.json` updates.                                                                                                        |
+| `npmDedupe`                  | Run `npm install` with `--prefer-dedupe` for npm >= 7 or `npm dedupe` after `package-lock.json` update for npm <= 6.                                       |
 | `pnpmDedupe`                 | Run `pnpm dedupe --config.ignore-scripts=true` after `pnpm-lock.yaml` updates.                                                                             |
 | `yarnDedupeFewer`            | Run `yarn-deduplicate --strategy fewer` after `yarn.lock` updates.                                                                                         |
 | `yarnDedupeHighest`          | Run `yarn-deduplicate --strategy highest` (`yarn dedupe --strategy highest` for Yarn >=2.2.0) after `yarn.lock` updates.                                   |
diff --git a/lib/modules/manager/npm/post-update/__snapshots__/npm.spec.ts.snap b/lib/modules/manager/npm/post-update/__snapshots__/npm.spec.ts.snap
index 83ccde3506e1b63e0ade46704181c83629e78153..459c4f599bade83e40ff22f60262d5648a8b71a6 100644
--- a/lib/modules/manager/npm/post-update/__snapshots__/npm.spec.ts.snap
+++ b/lib/modules/manager/npm/post-update/__snapshots__/npm.spec.ts.snap
@@ -3,25 +3,7 @@
 exports[`modules/manager/npm/post-update/npm generates lock files 1`] = `
 [
   {
-    "cmd": "npm install --no-audit --ignore-scripts",
-    "options": {
-      "cwd": "some-dir",
-      "encoding": "utf-8",
-      "env": {
-        "HOME": "/home/user",
-        "HTTPS_PROXY": "https://example.com",
-        "HTTP_PROXY": "http://example.com",
-        "LANG": "en_US.UTF-8",
-        "LC_ALL": "en_US",
-        "NO_PROXY": "localhost",
-        "PATH": "/tmp/path",
-      },
-      "maxBuffer": 10485760,
-      "timeout": 900000,
-    },
-  },
-  {
-    "cmd": "npm dedupe",
+    "cmd": "npm install --package-lock-only --no-audit --prefer-dedupe --ignore-scripts",
     "options": {
       "cwd": "some-dir",
       "encoding": "utf-8",
diff --git a/lib/modules/manager/npm/post-update/npm.spec.ts b/lib/modules/manager/npm/post-update/npm.spec.ts
index ffa0273a2a84908dc8da9f23e84f73f5af980fd5..7bff57fb2d12b0826e275db8b7a12b44317daa5c 100644
--- a/lib/modules/manager/npm/post-update/npm.spec.ts
+++ b/lib/modules/manager/npm/post-update/npm.spec.ts
@@ -162,6 +162,62 @@ describe('modules/manager/npm/post-update/npm', () => {
     expect(execSnapshots).toEqual([]);
   });
 
+  it('deduplicates dependencies on installation with npm >= 7', async () => {
+    const execSnapshots = mockExecAll();
+    // package.json
+    fs.readLocalFile.mockResolvedValueOnce('{}');
+    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    const postUpdateOptions = ['npmDedupe'];
+    const updates = [
+      { packageName: 'some-dep', newVersion: '1.0.1', isLockfileUpdate: false },
+    ];
+    const res = await npmHelper.generateLockFile(
+      'some-dir',
+      {},
+      'package-lock.json',
+      { postUpdateOptions },
+      updates
+    );
+    expect(fs.readLocalFile).toHaveBeenCalledTimes(2);
+    expect(res.error).toBeFalse();
+    expect(res.lockFile).toBe('package-lock-contents');
+    expect(execSnapshots).toHaveLength(1);
+    expect(execSnapshots).toMatchObject([
+      {
+        cmd: 'npm install --package-lock-only --no-audit --prefer-dedupe --ignore-scripts',
+      },
+    ]);
+  });
+
+  it('deduplicates dependencies after installation with npm <= 6', async () => {
+    const execSnapshots = mockExecAll();
+    // package.json
+    fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
+    const postUpdateOptions = ['npmDedupe'];
+    const updates = [
+      { packageName: 'some-dep', newVersion: '1.0.1', isLockfileUpdate: false },
+    ];
+    const res = await npmHelper.generateLockFile(
+      'some-dir',
+      {},
+      'package-lock.json',
+      { postUpdateOptions, constraints: { npm: '^6.0.0' } },
+      updates
+    );
+    expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
+    expect(res.error).toBeFalse();
+    expect(res.lockFile).toBe('package-lock-contents');
+    expect(execSnapshots).toHaveLength(2);
+    expect(execSnapshots).toMatchObject([
+      {
+        cmd: 'npm install --no-audit --ignore-scripts',
+      },
+      {
+        cmd: 'npm dedupe',
+      },
+    ]);
+  });
+
   it('runs twice if remediating', async () => {
     const execSnapshots = mockExecAll();
     fs.readLocalFile.mockResolvedValueOnce('package-lock-contents');
diff --git a/lib/modules/manager/npm/post-update/npm.ts b/lib/modules/manager/npm/post-update/npm.ts
index f81921d8eb75f1d737ee3b069db8f75ed3cd3f82..fd2b7b3f7b1b7d56f16bffa3757d51290c7f6692 100644
--- a/lib/modules/manager/npm/post-update/npm.ts
+++ b/lib/modules/manager/npm/post-update/npm.ts
@@ -1,5 +1,6 @@
 // TODO: types (#22198)
 import is from '@sindresorhus/is';
+import semver from 'semver';
 import upath from 'upath';
 import { GlobalConfig } from '../../../../config/global';
 import {
@@ -49,10 +50,14 @@ export async function generateLockFile(
         config.constraints?.npm ??
         getPackageManagerVersion('npm', await lazyPgkJson.getValue()),
     };
+    const supportsPreferDedupeFlag =
+      !npmToolConstraint.constraint ||
+      semver.intersects('>=7.0.0', npmToolConstraint.constraint);
     const commands: string[] = [];
     let cmdOptions = '';
     if (
-      postUpdateOptions?.includes('npmDedupe') === true ||
+      (postUpdateOptions?.includes('npmDedupe') === true &&
+        !supportsPreferDedupeFlag) ||
       skipInstalls === false
     ) {
       logger.debug('Performing node_modules install');
@@ -62,6 +67,11 @@ export async function generateLockFile(
       cmdOptions += '--package-lock-only --no-audit';
     }
 
+    if (postUpdateOptions?.includes('npmDedupe') && supportsPreferDedupeFlag) {
+      logger.debug('Deduplicate dependencies on installation');
+      cmdOptions += ' --prefer-dedupe';
+    }
+
     if (!GlobalConfig.get('allowScripts') || config.ignoreScripts) {
       cmdOptions += ' --ignore-scripts';
     }
@@ -130,8 +140,11 @@ export async function generateLockFile(
     }
 
     // postUpdateOptions
-    if (config.postUpdateOptions?.includes('npmDedupe')) {
-      logger.debug('Performing npm dedupe');
+    if (
+      config.postUpdateOptions?.includes('npmDedupe') &&
+      !supportsPreferDedupeFlag
+    ) {
+      logger.debug('Performing npm dedupe after installation');
       commands.push('npm dedupe');
     }