diff --git a/lib/modules/manager/npm/detect.spec.ts b/lib/modules/manager/npm/detect.spec.ts
index f6bf78700cc3691c086f043acfd9aea79e25552b..c38cbcb4f5e9d1d166ee3a7af474ca1fa4296c48 100644
--- a/lib/modules/manager/npm/detect.spec.ts
+++ b/lib/modules/manager/npm/detect.spec.ts
@@ -1,5 +1,5 @@
 import { fs } from '../../../../test/util';
-import { detectGlobalConfig } from './detect';
+import { detectGlobalConfig } from '.';
 
 jest.mock('../../../util/fs');
 
diff --git a/lib/modules/manager/npm/extract/index.spec.ts b/lib/modules/manager/npm/extract/index.spec.ts
index 016f8cdc7274e029953d66dfbe1d26e6971d88f2..2f5e4d73342417ea8799213cdce35f99684cf96a 100644
--- a/lib/modules/manager/npm/extract/index.spec.ts
+++ b/lib/modules/manager/npm/extract/index.spec.ts
@@ -165,7 +165,7 @@ describe('modules/manager/npm/extract/index', () => {
         'package.json',
         {}
       );
-      expect(res.npmrc).toBeDefined();
+      expect(res?.npmrc).toBeDefined();
     });
 
     it('ignores .npmrc when config.npmrc is defined and npmrcMerge=false', async () => {
@@ -180,7 +180,7 @@ describe('modules/manager/npm/extract/index', () => {
         'package.json',
         { npmrc: 'some-configured-npmrc' }
       );
-      expect(res.npmrc).toBeUndefined();
+      expect(res?.npmrc).toBeUndefined();
     });
 
     it('reads .npmrc when config.npmrc is merged', async () => {
@@ -195,7 +195,7 @@ describe('modules/manager/npm/extract/index', () => {
         'package.json',
         { npmrc: 'config-npmrc', npmrcMerge: true }
       );
-      expect(res.npmrc).toBe(`config-npmrc\nrepo-npmrc\n`);
+      expect(res?.npmrc).toBe(`config-npmrc\nrepo-npmrc\n`);
     });
 
     it('finds and filters .npmrc with variables', async () => {
@@ -210,7 +210,7 @@ describe('modules/manager/npm/extract/index', () => {
         'package.json',
         {}
       );
-      expect(res.npmrc).toBe('registry=https://registry.npmjs.org\n');
+      expect(res?.npmrc).toBe('registry=https://registry.npmjs.org\n');
     });
 
     it('finds lerna', async () => {
diff --git a/lib/modules/manager/npm/post-update/node-version.spec.ts b/lib/modules/manager/npm/post-update/node-version.spec.ts
index 55bba94a62c2acf6b754fdca9992bf9eb9ad4691..fc222af12a04847a00e62572b909e3543fe7a110 100644
--- a/lib/modules/manager/npm/post-update/node-version.spec.ts
+++ b/lib/modules/manager/npm/post-update/node-version.spec.ts
@@ -1,5 +1,5 @@
 import { fs } from '../../../../../test/util';
-import { getNodeConstraint } from './node-version';
+import { getNodeConstraint, getNodeUpdate } from './node-version';
 
 jest.mock('../../../../util/fs');
 
@@ -9,42 +9,51 @@ describe('modules/manager/npm/post-update/node-version', () => {
     constraints: { node: '^12.16.0' },
   };
 
-  it('returns package.json range', async () => {
-    fs.readLocalFile = jest.fn();
-    fs.readLocalFile.mockResolvedValueOnce(null);
-    fs.readLocalFile.mockResolvedValueOnce(null);
-    const res = await getNodeConstraint(config);
-    expect(res).toBe('^12.16.0');
-  });
+  describe('getNodeConstraint()', () => {
+    it('returns package.json range', async () => {
+      fs.readLocalFile.mockResolvedValueOnce(null as never);
+      fs.readLocalFile.mockResolvedValueOnce(null as never);
+      const res = await getNodeConstraint(config);
+      expect(res).toBe('^12.16.0');
+    });
 
-  it('returns .node-version value', async () => {
-    fs.readLocalFile = jest.fn();
-    fs.readLocalFile.mockResolvedValueOnce(null);
-    fs.readLocalFile.mockResolvedValueOnce('12.16.1\n');
-    const res = await getNodeConstraint(config);
-    expect(res).toBe('12.16.1');
-  });
+    it('returns .node-version value', async () => {
+      fs.readLocalFile.mockResolvedValueOnce(null as never);
+      fs.readLocalFile.mockResolvedValueOnce('12.16.1\n');
+      const res = await getNodeConstraint(config);
+      expect(res).toBe('12.16.1');
+    });
 
-  it('returns .nvmrc value', async () => {
-    fs.readLocalFile = jest.fn();
-    fs.readLocalFile.mockResolvedValueOnce('12.16.2\n');
-    const res = await getNodeConstraint(config);
-    expect(res).toBe('12.16.2');
-  });
+    it('returns .nvmrc value', async () => {
+      fs.readLocalFile.mockResolvedValueOnce('12.16.2\n');
+      const res = await getNodeConstraint(config);
+      expect(res).toBe('12.16.2');
+    });
 
-  it('ignores unusable ranges in dotfiles', async () => {
-    fs.readLocalFile = jest.fn();
-    fs.readLocalFile.mockResolvedValueOnce('latest');
-    fs.readLocalFile.mockResolvedValueOnce('lts');
-    const res = await getNodeConstraint(config);
-    expect(res).toBe('^12.16.0');
+    it('ignores unusable ranges in dotfiles', async () => {
+      fs.readLocalFile.mockResolvedValueOnce('latest');
+      fs.readLocalFile.mockResolvedValueOnce('lts');
+      const res = await getNodeConstraint(config);
+      expect(res).toBe('^12.16.0');
+    });
+
+    it('returns no constraint', async () => {
+      fs.readLocalFile.mockResolvedValueOnce(null as never);
+      fs.readLocalFile.mockResolvedValueOnce(null as never);
+      const res = await getNodeConstraint({ ...config, constraints: null });
+      expect(res).toBeNull();
+    });
   });
 
-  it('returns no constraint', async () => {
-    fs.readLocalFile = jest.fn();
-    fs.readLocalFile.mockResolvedValueOnce(null);
-    fs.readLocalFile.mockResolvedValueOnce(null);
-    const res = await getNodeConstraint({ ...config, constraints: null });
-    expect(res).toBeNull();
+  describe('getNodeUpdate()', () => {
+    it('returns version', () => {
+      expect(getNodeUpdate([{ depName: 'node', newValue: '16.15.0' }])).toBe(
+        '16.15.0'
+      );
+    });
+
+    it('returns undefined', () => {
+      expect(getNodeUpdate([])).toBeUndefined();
+    });
   });
 });
diff --git a/lib/modules/manager/npm/post-update/node-version.ts b/lib/modules/manager/npm/post-update/node-version.ts
index ad4f4b168182ff91fb9bdc80f19d065b08bf00e3..f35cbaab40721a315fb942b8bf1c8143f8422319 100644
--- a/lib/modules/manager/npm/post-update/node-version.ts
+++ b/lib/modules/manager/npm/post-update/node-version.ts
@@ -2,7 +2,7 @@ import semver from 'semver';
 import { logger } from '../../../../logger';
 import { getSiblingFileName, readLocalFile } from '../../../../util/fs';
 import { newlineRegex, regEx } from '../../../../util/regex';
-import type { PostUpdateConfig } from '../../types';
+import type { PostUpdateConfig, Upgrade } from '../../types';
 
 async function getNodeFile(filename: string): Promise<string | null> {
   try {
@@ -43,3 +43,7 @@ export async function getNodeConstraint(
   }
   return constraint;
 }
+
+export function getNodeUpdate(upgrades: Upgrade[]): string | undefined {
+  return upgrades.find((u) => u.depName === 'node')?.newValue;
+}
diff --git a/lib/modules/manager/npm/post-update/npm.ts b/lib/modules/manager/npm/post-update/npm.ts
index ca4ea0ad5a725bb659074ee9712d0250dd624dcb..6bc9e8bdf8592caff39eb076ceaaecdc5994a0ad 100644
--- a/lib/modules/manager/npm/post-update/npm.ts
+++ b/lib/modules/manager/npm/post-update/npm.ts
@@ -19,7 +19,7 @@ import {
 } from '../../../../util/fs';
 import type { PostUpdateConfig, Upgrade } from '../../types';
 import { composeLockFile, parseLockFile } from '../utils';
-import { getNodeConstraint } from './node-version';
+import { getNodeConstraint, getNodeUpdate } from './node-version';
 import type { GenerateLockFileResult } from './types';
 
 export async function generateLockFile(
@@ -55,7 +55,8 @@ export async function generateLockFile(
       cmdOptions += ' --ignore-scripts';
     }
 
-    const tagConstraint = await getNodeConstraint(config);
+    const tagConstraint =
+      getNodeUpdate(upgrades) ?? (await getNodeConstraint(config));
     const extraEnv: ExtraEnv = {
       NPM_CONFIG_CACHE: env.NPM_CONFIG_CACHE,
       npm_config_store: env.npm_config_store,
diff --git a/lib/modules/manager/npm/post-update/pnpm.ts b/lib/modules/manager/npm/post-update/pnpm.ts
index 4b61b802448da9c24d934cabaa24db4288566ab5..3dc3c808586dc7b4719184bbc36680366b24b36d 100644
--- a/lib/modules/manager/npm/post-update/pnpm.ts
+++ b/lib/modules/manager/npm/post-update/pnpm.ts
@@ -13,7 +13,7 @@ import type {
 import { deleteLocalFile, readLocalFile } from '../../../../util/fs';
 import type { PostUpdateConfig, Upgrade } from '../../types';
 import type { NpmPackage } from '../extract/types';
-import { getNodeConstraint } from './node-version';
+import { getNodeConstraint, getNodeUpdate } from './node-version';
 import type { GenerateLockFileResult, PnpmLockFile } from './types';
 
 export async function generateLockFile(
@@ -34,7 +34,8 @@ export async function generateLockFile(
       constraint:
         config.constraints?.pnpm ?? (await getPnpmContraint(lockFileDir)),
     };
-    const tagConstraint = await getNodeConstraint(config);
+    const tagConstraint =
+      getNodeUpdate(upgrades) ?? (await getNodeConstraint(config));
     const extraEnv: ExtraEnv = {
       NPM_CONFIG_CACHE: env.NPM_CONFIG_CACHE,
       npm_config_store: env.npm_config_store,
diff --git a/lib/modules/manager/npm/post-update/yarn.ts b/lib/modules/manager/npm/post-update/yarn.ts
index 5a2bbffb03c9025dc84b78fca7481af00808b9cd..173c1ece1a90cda84095010b43cadd3dcb6a00a4 100644
--- a/lib/modules/manager/npm/post-update/yarn.ts
+++ b/lib/modules/manager/npm/post-update/yarn.ts
@@ -26,7 +26,7 @@ import { uniqueStrings } from '../../../../util/string';
 import { NpmDatasource } from '../../../datasource/npm';
 import type { PostUpdateConfig, Upgrade } from '../../types';
 import type { NpmManagerData } from '../types';
-import { getNodeConstraint } from './node-version';
+import { getNodeConstraint, getNodeUpdate } from './node-version';
 import type { GenerateLockFileResult } from './types';
 
 export async function checkYarnrc(
@@ -175,7 +175,8 @@ export async function generateLockFile(
         extraEnv.YARN_ENABLE_SCRIPTS = '0';
       }
     }
-    const tagConstraint = await getNodeConstraint(config);
+    const tagConstraint =
+      getNodeUpdate(upgrades) ?? (await getNodeConstraint(config));
     const execOptions: ExecOptions = {
       cwdFile: lockFileName,
       extraEnv,
diff --git a/lib/modules/manager/npm/update/dependency/index.spec.ts b/lib/modules/manager/npm/update/dependency/index.spec.ts
index c5a5187886110a58099843500462823009c49c43..fd1223261fece0351a8d92a590edf1cbe46956e4 100644
--- a/lib/modules/manager/npm/update/dependency/index.spec.ts
+++ b/lib/modules/manager/npm/update/dependency/index.spec.ts
@@ -1,5 +1,6 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+import * as npmUpdater from '../..';
 import { Fixtures } from '../../../../../../test/fixtures';
-import * as npmUpdater from '.';
 
 const readFixture = (x: string): string => Fixtures.get(x, '../..');
 
@@ -41,7 +42,7 @@ describe('modules/manager/npm/update/dependency/index', () => {
         upgrade,
       });
       expect(res).toBeJsonString();
-      expect(JSON.parse(res)).toEqual({
+      expect(JSON.parse(res!)).toEqual({
         dependencies: { gulp: 'gulpjs/gulp#v4.0.0' },
       });
     });
@@ -65,7 +66,7 @@ describe('modules/manager/npm/update/dependency/index', () => {
         upgrade,
       });
       expect(res).toBeJsonString();
-      expect(JSON.parse(res)).toEqual({
+      expect(JSON.parse(res!)).toEqual({
         dependencies: { hapi: 'npm:@hapi/hapi@18.3.1' },
       });
     });
@@ -88,7 +89,7 @@ describe('modules/manager/npm/update/dependency/index', () => {
         upgrade,
       });
       expect(res).toBeJsonString();
-      expect(JSON.parse(res)).toEqual({
+      expect(JSON.parse(res!)).toEqual({
         dependencies: { gulp: 'gulpjs/gulp#0000000' },
       });
     });
@@ -124,8 +125,8 @@ describe('modules/manager/npm/update/dependency/index', () => {
         fileContent: input01Content,
         upgrade,
       });
-      expect(JSON.parse(testContent).dependencies.config).toBe('1.22.0');
-      expect(JSON.parse(testContent).resolutions.config).toBe('1.22.0');
+      expect(JSON.parse(testContent!).dependencies.config).toBe('1.22.0');
+      expect(JSON.parse(testContent!).resolutions.config).toBe('1.22.0');
     });
 
     it('updates glob resolutions', () => {
@@ -138,8 +139,8 @@ describe('modules/manager/npm/update/dependency/index', () => {
         fileContent: input01GlobContent,
         upgrade,
       });
-      expect(JSON.parse(testContent).dependencies.config).toBe('1.22.0');
-      expect(JSON.parse(testContent).resolutions['**/config']).toBe('1.22.0');
+      expect(JSON.parse(testContent!).dependencies.config).toBe('1.22.0');
+      expect(JSON.parse(testContent!).resolutions['**/config']).toBe('1.22.0');
     });
 
     it('updates glob resolutions without dep', () => {
@@ -153,7 +154,7 @@ describe('modules/manager/npm/update/dependency/index', () => {
         fileContent: input01Content,
         upgrade,
       });
-      expect(JSON.parse(testContent).resolutions['**/@angular/cli']).toBe(
+      expect(JSON.parse(testContent!).resolutions['**/@angular/cli']).toBe(
         '8.1.0'
       );
     });
@@ -233,7 +234,7 @@ describe('modules/manager/npm/update/dependency/index', () => {
         newValue: '1.5.8',
       };
       const testContent = npmUpdater.updateDependency({
-        fileContent: null,
+        fileContent: null as never,
         upgrade,
       });
       expect(testContent).toBeNull();
@@ -250,8 +251,8 @@ describe('modules/manager/npm/update/dependency/index', () => {
         fileContent: input01Content,
         upgrade,
       });
-      expect(JSON.parse(testContent).dependencies.config).toBeUndefined();
-      expect(JSON.parse(testContent).dependencies.abc).toBe('2.0.0');
+      expect(JSON.parse(testContent!).dependencies.config).toBeUndefined();
+      expect(JSON.parse(testContent!).dependencies.abc).toBe('2.0.0');
     });
 
     it('replaces glob package resolutions', () => {
@@ -265,8 +266,8 @@ describe('modules/manager/npm/update/dependency/index', () => {
         fileContent: input01GlobContent,
         upgrade,
       });
-      expect(JSON.parse(testContent).resolutions.config).toBeUndefined();
-      expect(JSON.parse(testContent).resolutions['**/abc']).toBe('2.0.0');
+      expect(JSON.parse(testContent!).resolutions.config).toBeUndefined();
+      expect(JSON.parse(testContent!).resolutions['**/abc']).toBe('2.0.0');
     });
 
     it('pins also the version in patch with npm protocol in resolutions', () => {
diff --git a/lib/modules/manager/npm/update/locked-dependency/index.spec.ts b/lib/modules/manager/npm/update/locked-dependency/index.spec.ts
index 114183121949c82eb55c5d028377cb28628c384e..08f8f76b25996438903b61bb3fc02c873fe1a466 100644
--- a/lib/modules/manager/npm/update/locked-dependency/index.spec.ts
+++ b/lib/modules/manager/npm/update/locked-dependency/index.spec.ts
@@ -1,8 +1,9 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-assertion */
+import { updateLockedDependency } from '../..';
 import * as httpMock from '../../../../../../test/http-mock';
 import { loadFixture } from '../../../../../../test/util';
 import { clone } from '../../../../../util/clone';
 import type { UpdateLockedConfig } from '../../../types';
-import { updateLockedDependency } from '.';
 
 const packageFileContent = loadFixture('package.json', './package-lock');
 const lockFileContent = loadFixture('package-lock.json', './package-lock');
@@ -97,7 +98,7 @@ describe('modules/manager/npm/update/locked-dependency/index', () => {
         newVersion: '1.2.12',
       });
       expect(
-        JSON.parse(res.files['package-lock.json']).dependencies.mime.version
+        JSON.parse(res.files!['package-lock.json']).dependencies.mime.version
       ).toBe('1.2.12');
     });
 
@@ -137,8 +138,8 @@ describe('modules/manager/npm/update/locked-dependency/index', () => {
       config.currentVersion = '4.0.0';
       config.newVersion = '4.1.0';
       const res = await updateLockedDependency(config);
-      expect(res.files['package.json']).toContain('"express": "4.1.0"');
-      const packageLock = JSON.parse(res.files['package-lock.json']);
+      expect(res.files!['package.json']).toContain('"express": "4.1.0"');
+      const packageLock = JSON.parse(res.files!['package-lock.json']);
       expect(packageLock.dependencies.express.version).toBe('4.1.0');
     });
 
@@ -148,8 +149,8 @@ describe('modules/manager/npm/update/locked-dependency/index', () => {
       config.newVersion = '4.1.0';
       config.lockFileContent = lockFileV2Content;
       const res = await updateLockedDependency(config);
-      expect(res.files['package.json']).toContain('"express": "4.1.0"');
-      const packageLock = JSON.parse(res.files['package-lock.json']);
+      expect(res.files!['package.json']).toContain('"express": "4.1.0"');
+      const packageLock = JSON.parse(res.files!['package-lock.json']);
       expect(packageLock.dependencies.express.version).toBe('4.1.0');
     });
 
@@ -218,7 +219,7 @@ describe('modules/manager/npm/update/locked-dependency/index', () => {
         .get('/type-is')
         .reply(200, typeIsJson);
       const res = await updateLockedDependency(config);
-      const packageLock = JSON.parse(res.files['package-lock.json']);
+      const packageLock = JSON.parse(res.files!['package-lock.json']);
       expect(packageLock.dependencies.mime.version).toBe('1.4.1');
       expect(packageLock.dependencies.express.version).toBe('4.16.0');
     });
diff --git a/lib/modules/manager/npm/update/package-version/index.spec.ts b/lib/modules/manager/npm/update/package-version/index.spec.ts
index 4de57ba062687c9446d224a361f9d68f8582d9fc..53829adc47b389075aad45d63040f05d49f42291 100644
--- a/lib/modules/manager/npm/update/package-version/index.spec.ts
+++ b/lib/modules/manager/npm/update/package-version/index.spec.ts
@@ -1,4 +1,4 @@
-import * as npmUpdater from '.';
+import * as npmUpdater from '../..';
 
 describe('modules/manager/npm/update/package-version/index', () => {
   describe('.bumpPackageVersion()', () => {