diff --git a/lib/modules/manager/npm/extract/index.spec.ts b/lib/modules/manager/npm/extract/index.spec.ts
index 7f90f02c3d3d8b498840ae36de1d15c21e5922ab..0529099f6f027e3021ebeaeb3a5fa3e81b687801 100644
--- a/lib/modules/manager/npm/extract/index.spec.ts
+++ b/lib/modules/manager/npm/extract/index.spec.ts
@@ -165,25 +165,35 @@ describe('modules/manager/npm/extract/index', () => {
         'package.json',
         {}
       );
-      expect(res?.npmrc).toBeDefined();
+      expect(res?.npmrc).toBe('save-exact = true\n');
     });
 
-    it('ignores .npmrc when config.npmrc is defined and npmrcMerge=false', async () => {
+    it('uses config.npmrc if no .npmrc exists', async () => {
+      fs.readLocalFile = jest.fn(() => null);
+      const res = await npmExtract.extractPackageFile(
+        input01Content,
+        'package.json',
+        { ...defaultConfig, npmrc: 'config-npmrc' }
+      );
+      expect(res?.npmrc).toBe('config-npmrc');
+    });
+
+    it('uses config.npmrc if .npmrc does exist but npmrcMerge=false', async () => {
       fs.readLocalFile = jest.fn((fileName) => {
         if (fileName === '.npmrc') {
-          return 'some-npmrc\n';
+          return 'repo-npmrc\n';
         }
         return null;
       });
       const res = await npmExtract.extractPackageFile(
         input01Content,
         'package.json',
-        { npmrc: 'some-configured-npmrc' }
+        { npmrc: 'config-npmrc' }
       );
-      expect(res?.npmrc).toBeUndefined();
+      expect(res?.npmrc).toBe('config-npmrc');
     });
 
-    it('reads .npmrc when config.npmrc is merged', async () => {
+    it('merges config.npmrc and repo .npmrc when npmrcMerge=true', async () => {
       fs.readLocalFile = jest.fn((fileName) => {
         if (fileName === '.npmrc') {
           return 'repo-npmrc\n';
diff --git a/lib/modules/manager/npm/extract/index.ts b/lib/modules/manager/npm/extract/index.ts
index 89e3a71bc59db94b4e5b793cf0268e7914200660..a69b98eac1573eb6df1a66e4ab4d29d0a4a84a5a 100644
--- a/lib/modules/manager/npm/extract/index.ts
+++ b/lib/modules/manager/npm/extract/index.ts
@@ -104,6 +104,7 @@ export async function extractPackageFile(
         { npmrcFileName },
         'Repo .npmrc file is ignored due to config.npmrc with config.npmrcMerge=false'
       );
+      npmrc = config.npmrc;
     } else {
       npmrc = config.npmrc ?? '';
       if (npmrc.length) {
@@ -130,6 +131,8 @@ export async function extractPackageFile(
       }
       npmrc += repoNpmrc;
     }
+  } else if (is.string(config.npmrc)) {
+    npmrc = config.npmrc;
   }
 
   const yarnrcYmlFileName = getSiblingFileName(fileName, '.yarnrc.yml');
diff --git a/lib/modules/manager/npm/post-update/index.spec.ts b/lib/modules/manager/npm/post-update/index.spec.ts
index 549e387449cb278bf708b2f2301cf73aa5514991..dd2b97131086cfa8f976ef0134869ca4a6c6646d 100644
--- a/lib/modules/manager/npm/post-update/index.spec.ts
+++ b/lib/modules/manager/npm/post-update/index.spec.ts
@@ -219,6 +219,43 @@ describe('modules/manager/npm/post-update/index', () => {
       ]);
     });
 
+    it('writes .npmrc files', async () => {
+      await writeExistingFiles(updateConfig, {
+        npm: [
+          // This package's npmrc should be written verbatim.
+          { packageFile: 'packages/core/package.json', npmrc: '#dummy' },
+          // No npmrc content should be written for this package.
+          { packageFile: 'packages/core/package.json' },
+        ],
+      });
+
+      expect(fs.writeLocalFile).toHaveBeenCalledOnce();
+      expect(fs.writeLocalFile).toHaveBeenCalledWith(
+        'packages/core/.npmrc',
+        '#dummy\n'
+      );
+    });
+
+    it('only sources npmrc content from package config', async () => {
+      await writeExistingFiles(
+        { ...updateConfig, npmrc: '#foobar' },
+        {
+          npm: [
+            // This package's npmrc should be written verbatim.
+            { packageFile: 'packages/core/package.json', npmrc: '#dummy' },
+            // No npmrc content should be written for this package.
+            { packageFile: 'packages/core/package.json' },
+          ],
+        }
+      );
+
+      expect(fs.writeLocalFile).toHaveBeenCalledOnce();
+      expect(fs.writeLocalFile).toHaveBeenCalledWith(
+        'packages/core/.npmrc',
+        '#dummy\n'
+      );
+    });
+
     it('works only on relevant folders', async () => {
       git.getFile.mockResolvedValueOnce(
         Fixtures.get('update-lockfile-massage-1/package-lock.json')
diff --git a/lib/modules/manager/npm/post-update/index.ts b/lib/modules/manager/npm/post-update/index.ts
index 0f15c4fc41301e8c6a97d0d6f8716d2807df1c53..4eeb36b10c796c5e8784ddb21abff9b09be9dbf2 100644
--- a/lib/modules/manager/npm/post-update/index.ts
+++ b/lib/modules/manager/npm/post-update/index.ts
@@ -143,7 +143,7 @@ export async function writeExistingFiles(
   for (const packageFile of npmFiles) {
     // TODO #7154
     const basedir = upath.dirname(packageFile.packageFile!);
-    const npmrc: string = packageFile.npmrc ?? config.npmrc;
+    const npmrc = packageFile.npmrc;
     const npmrcFilename = upath.join(basedir, '.npmrc');
     if (is.string(npmrc)) {
       try {