diff --git a/lib/config/presets/npm/index.ts b/lib/config/presets/npm/index.ts
index 959582869459131fcc8adb825e983514031c13d5..6c9b5cc508d51ae542a900d73d668d7a564d48f0 100644
--- a/lib/config/presets/npm/index.ts
+++ b/lib/config/presets/npm/index.ts
@@ -1,5 +1,8 @@
 import { logger } from '../../../logger';
-import { resolvePackage } from '../../../modules/datasource/npm/npmrc';
+import {
+  resolvePackageUrl,
+  resolveRegistryUrl,
+} from '../../../modules/datasource/npm/npmrc';
 import type { NpmResponse } from '../../../modules/datasource/npm/types';
 import { Http } from '../../../util/http';
 import type { Preset, PresetConfig } from '../types';
@@ -19,7 +22,8 @@ export async function getPreset({
 }: PresetConfig): Promise<Preset> {
   let dep;
   try {
-    const { packageUrl } = resolvePackage(pkg);
+    const registryUrl = resolveRegistryUrl(pkg);
+    const packageUrl = resolvePackageUrl(registryUrl, pkg);
     // istanbul ignore if
     if (!packageUrl.startsWith('https://registry.npmjs.org/')) {
       logger.warn(
diff --git a/lib/modules/datasource/index.ts b/lib/modules/datasource/index.ts
index e2fd5fa40db8a77f9b7989716a4db71b4ce39de0..3a65c3c9e3fb5a8b8e3650b040061b85cbf782a5 100644
--- a/lib/modules/datasource/index.ts
+++ b/lib/modules/datasource/index.ts
@@ -11,6 +11,8 @@ import { trimTrailingSlash } from '../../util/url';
 import * as allVersioning from '../versioning';
 import datasources from './api';
 import { addMetaData } from './metadata';
+import { setNpmrc } from './npm';
+import { resolveRegistryUrl } from './npm/npmrc';
 import type {
   DatasourceApi,
   DigestConfig,
@@ -239,15 +241,24 @@ async function fetchReleases(
   config: GetReleasesInternalConfig
 ): Promise<ReleaseResult | null> {
   const { datasource: datasourceName } = config;
+  let { registryUrls } = config;
   if (!datasourceName || getDatasourceFor(datasourceName) === undefined) {
     logger.warn('Unknown datasource: ' + datasourceName);
     return null;
   }
+  if (datasourceName === 'npm') {
+    if (is.string(config.npmrc)) {
+      setNpmrc(config.npmrc);
+    }
+    if (!is.nonEmptyArray(registryUrls)) {
+      registryUrls = [resolveRegistryUrl(config.packageName)];
+    }
+  }
   const datasource = getDatasourceFor(datasourceName);
-  const registryUrls = resolveRegistryUrls(
+  registryUrls = resolveRegistryUrls(
     datasource,
     config.defaultRegistryUrls,
-    config.registryUrls
+    registryUrls
   );
   let dep: ReleaseResult = null;
   const registryStrategy = datasource.registryStrategy || 'hunt';
diff --git a/lib/modules/datasource/npm/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/npm/__snapshots__/index.spec.ts.snap
index acf789ba8696b5df352ea3e364e29f29ba0dbca8..6228c47ed26395bd5789342e62d5f9c50b4c6848 100644
--- a/lib/modules/datasource/npm/__snapshots__/index.spec.ts.snap
+++ b/lib/modules/datasource/npm/__snapshots__/index.spec.ts.snap
@@ -19,7 +19,7 @@ Array [
 exports[`modules/datasource/npm/index should fetch package info from custom registry 1`] = `
 Object {
   "name": "foobar",
-  "registryUrl": "https://npm.mycustomregistry.com/",
+  "registryUrl": "https://npm.mycustomregistry.com",
   "releases": Array [
     Object {
       "releaseTimestamp": "2018-05-06T05:21:53.000Z",
@@ -561,7 +561,7 @@ Array [
 exports[`modules/datasource/npm/index should use host rules by baseUrl if provided 1`] = `
 Object {
   "name": "foobar",
-  "registryUrl": "https://npm.mycustomregistry.com/_packaging/mycustomregistry/npm/registry/",
+  "registryUrl": "https://npm.mycustomregistry.com/_packaging/mycustomregistry/npm/registry",
   "releases": Array [
     Object {
       "releaseTimestamp": "2018-05-06T05:21:53.000Z",
@@ -600,7 +600,7 @@ Array [
 exports[`modules/datasource/npm/index should use host rules by hostName if provided 1`] = `
 Object {
   "name": "foobar",
-  "registryUrl": "https://npm.mycustomregistry.com/",
+  "registryUrl": "https://npm.mycustomregistry.com",
   "releases": Array [
     Object {
       "releaseTimestamp": "2018-05-06T05:21:53.000Z",
diff --git a/lib/modules/datasource/npm/get.spec.ts b/lib/modules/datasource/npm/get.spec.ts
index ea0d27d83ad955ab7874e61daa7bde08f11e6a15..1c3dce29bef4ea7c886488f1285c5a64e8735f9a 100644
--- a/lib/modules/datasource/npm/get.spec.ts
+++ b/lib/modules/datasource/npm/get.spec.ts
@@ -3,7 +3,7 @@ import { ExternalHostError } from '../../../types/errors/external-host-error';
 import * as hostRules from '../../../util/host-rules';
 import { Http } from '../../../util/http';
 import { getDependency, resetMemCache } from './get';
-import { setNpmrc } from './npmrc';
+import { resolveRegistryUrl, setNpmrc } from './npmrc';
 
 function getPath(s = ''): string {
   const [x] = s.split('\n');
@@ -44,7 +44,8 @@ describe('modules/datasource/npm/get', () => {
         .reply(200, { name: '@myco/test' });
 
       setNpmrc(npmrc);
-      await getDependency(http, '@myco/test');
+      const registryUrl = resolveRegistryUrl('@myco/test');
+      await getDependency(http, registryUrl, '@myco/test');
 
       const trace = httpMock.getTrace();
       expect(trace[0].headers.authorization).toBe('Bearer XXX');
@@ -76,7 +77,8 @@ describe('modules/datasource/npm/get', () => {
         .get(getPath(npmrc))
         .reply(200, { name: '@myco/test' });
       setNpmrc(npmrc);
-      await getDependency(http, '@myco/test');
+      const registryUrl = resolveRegistryUrl('@myco/test');
+      await getDependency(http, registryUrl, '@myco/test');
 
       const trace = httpMock.getTrace();
       expect(trace[0].headers.authorization).toBe('Basic dGVzdDp0ZXN0');
@@ -99,7 +101,8 @@ describe('modules/datasource/npm/get', () => {
         .get(getPath(npmrc))
         .reply(200, { name: '@myco/test' });
       setNpmrc(npmrc);
-      await getDependency(http, '@myco/test');
+      const registryUrl = resolveRegistryUrl('@myco/test');
+      await getDependency(http, registryUrl, '@myco/test');
 
       const trace = httpMock.getTrace();
       expect(trace[0].headers.authorization).toBeUndefined();
@@ -125,7 +128,8 @@ describe('modules/datasource/npm/get', () => {
       .get(getPath(npmrc))
       .reply(200, { name: '@myco/test' });
     setNpmrc(npmrc);
-    await getDependency(http, '@myco/test');
+    const registryUrl = resolveRegistryUrl('@myco/test');
+    await getDependency(http, registryUrl, '@myco/test');
     expect(httpMock.getTrace()).toMatchSnapshot();
   });
 
@@ -146,7 +150,8 @@ describe('modules/datasource/npm/get', () => {
       .get('/renovate')
       .reply(200, { name: 'renovate' });
     setNpmrc(npmrc);
-    await getDependency(http, 'renovate');
+    const registryUrl = resolveRegistryUrl('renovate');
+    await getDependency(http, registryUrl, 'renovate');
     expect(httpMock.getTrace()).toMatchSnapshot();
   });
 
@@ -168,7 +173,8 @@ describe('modules/datasource/npm/get', () => {
       .get('/renovate')
       .reply(200, { name: 'renovate' });
     setNpmrc(npmrc);
-    await getDependency(http, 'renovate');
+    const registryUrl = resolveRegistryUrl('renovate');
+    await getDependency(http, registryUrl, 'renovate');
     expect(httpMock.getTrace()).toMatchSnapshot();
   });
 
@@ -181,7 +187,8 @@ describe('modules/datasource/npm/get', () => {
       .scope('https://test.org')
       .get('/none')
       .reply(200, { name: '@myco/test' });
-    expect(await getDependency(http, 'none')).toBeNull();
+    let registryUrl = resolveRegistryUrl('none');
+    expect(await getDependency(http, registryUrl, 'none')).toBeNull();
 
     httpMock
       .scope('https://test.org')
@@ -192,7 +199,8 @@ describe('modules/datasource/npm/get', () => {
         versions: { '1.0.0': {} },
         'dist-tags': { latest: '1.0.0' },
       });
-    expect(await getDependency(http, '@myco/test')).toBeDefined();
+    registryUrl = resolveRegistryUrl('@myco/test');
+    expect(await getDependency(http, registryUrl, '@myco/test')).toBeDefined();
 
     httpMock
       .scope('https://test.org')
@@ -202,34 +210,40 @@ describe('modules/datasource/npm/get', () => {
         versions: { '1.0.0': {} },
         'dist-tags': { latest: '1.0.0' },
       });
-    expect(await getDependency(http, '@myco/test2')).toBeDefined();
+    registryUrl = resolveRegistryUrl('@myco/test2');
+    expect(await getDependency(http, registryUrl, '@myco/test2')).toBeDefined();
 
     httpMock.scope('https://test.org').get('/error-401').reply(401);
-    expect(await getDependency(http, 'error-401')).toBeNull();
+    registryUrl = resolveRegistryUrl('error-401');
+    expect(await getDependency(http, registryUrl, 'error-401')).toBeNull();
 
     httpMock.scope('https://test.org').get('/error-402').reply(402);
-    expect(await getDependency(http, 'error-402')).toBeNull();
+    registryUrl = resolveRegistryUrl('error-402');
+    expect(await getDependency(http, registryUrl, 'error-402')).toBeNull();
 
     httpMock.scope('https://test.org').get('/error-404').reply(404);
-    expect(await getDependency(http, 'error-404')).toBeNull();
+    registryUrl = resolveRegistryUrl('error-404');
+    expect(await getDependency(http, registryUrl, 'error-404')).toBeNull();
 
     httpMock.scope('https://test.org').get('/error4').reply(200, null);
-    expect(await getDependency(http, 'error4')).toBeNull();
+    registryUrl = resolveRegistryUrl('error4');
+    expect(await getDependency(http, registryUrl, 'error4')).toBeNull();
 
     setNpmrc();
     httpMock
       .scope('https://registry.npmjs.org')
       .get('/npm-parse-error')
       .reply(200, 'not-a-json');
-    await expect(getDependency(http, 'npm-parse-error')).rejects.toThrow(
-      ExternalHostError
-    );
+    registryUrl = resolveRegistryUrl('npm-parse-error');
+    await expect(
+      getDependency(http, registryUrl, 'npm-parse-error')
+    ).rejects.toThrow(ExternalHostError);
 
     httpMock
       .scope('https://registry.npmjs.org')
       .get('/npm-error-402')
       .reply(402);
-    expect(await getDependency(http, 'npm-error-402')).toBeNull();
+    expect(await getDependency(http, registryUrl, 'npm-error-402')).toBeNull();
 
     expect(httpMock.getTrace()).toMatchSnapshot();
   });
@@ -249,8 +263,8 @@ describe('modules/datasource/npm/get', () => {
         versions: { '1.0.0': {} },
         'dist-tags': { latest: '1.0.0' },
       });
-
-    const dep = await getDependency(http, '@neutrinojs/react');
+    const registryUrl = resolveRegistryUrl('@neutrinojs/react');
+    const dep = await getDependency(http, registryUrl, '@neutrinojs/react');
 
     expect(dep.sourceUrl).toBe('https://github.com/neutrinojs/neutrino');
     expect(dep.sourceDirectory).toBe('packages/react');
@@ -300,8 +314,8 @@ describe('modules/datasource/npm/get', () => {
         },
         'dist-tags': { latest: '2.0.0' },
       });
-
-    const dep = await getDependency(http, 'vue');
+    const registryUrl = resolveRegistryUrl('vue');
+    const dep = await getDependency(http, registryUrl, 'vue');
 
     expect(dep.sourceUrl).toBe('https://github.com/vuejs/vue.git');
     expect(dep.releases[0].sourceUrl).toBeUndefined();
@@ -326,8 +340,8 @@ describe('modules/datasource/npm/get', () => {
         versions: { '1.0.0': {} },
         'dist-tags': { latest: '1.0.0' },
       });
-
-    const dep = await getDependency(http, '@neutrinojs/react');
+    const registryUrl = resolveRegistryUrl('@neutrinojs/react');
+    const dep = await getDependency(http, registryUrl, '@neutrinojs/react');
 
     expect(dep.sourceUrl).toBe('https://github.com/neutrinojs/neutrino');
     expect(dep.sourceDirectory).toBe('packages/foo');
@@ -364,8 +378,8 @@ describe('modules/datasource/npm/get', () => {
         versions: { '1.0.0': {} },
         'dist-tags': { latest: '1.0.0' },
       });
-
-    const dep = await getDependency(http, '@neutrinojs/react');
+    const registryUrl = resolveRegistryUrl('@neutrinojs/react');
+    const dep = await getDependency(http, registryUrl, '@neutrinojs/react');
 
     expect(dep.sourceUrl).toBe(
       'https://bitbucket.org/neutrinojs/neutrino/tree/master/packages/react'
diff --git a/lib/modules/datasource/npm/get.ts b/lib/modules/datasource/npm/get.ts
index 1c20f1d65b6efa22f8bb949fef9880eb1ab0b214..44d1c7aa93b81c66c6b0b285f3bf7d6f05dd84b7 100644
--- a/lib/modules/datasource/npm/get.ts
+++ b/lib/modules/datasource/npm/get.ts
@@ -4,8 +4,8 @@ import { logger } from '../../../logger';
 import { ExternalHostError } from '../../../types/errors/external-host-error';
 import * as packageCache from '../../../util/cache/package';
 import type { Http } from '../../../util/http';
+import { joinUrlParts } from '../../../util/url';
 import { id } from './common';
-import { resolvePackage } from './npmrc';
 import type { NpmDependency, NpmRelease, NpmResponse } from './types';
 
 let memcache: Record<string, string> = {};
@@ -52,6 +52,7 @@ function getPackageSource(repository: any): PackageSource {
 
 export async function getDependency(
   http: Http,
+  registryUrl: string,
   packageName: string
 ): Promise<NpmDependency | null> {
   logger.trace(`npm.getDependency(${packageName})`);
@@ -62,7 +63,7 @@ export async function getDependency(
     return JSON.parse(memcache[packageName]) as NpmDependency;
   }
 
-  const { packageUrl, registryUrl } = resolvePackage(packageName);
+  const packageUrl = joinUrlParts(registryUrl, packageName.replace('/', '%2F'));
 
   // Now check the persistent cache
   const cacheNamespace = 'datasource-npm';
diff --git a/lib/modules/datasource/npm/index.ts b/lib/modules/datasource/npm/index.ts
index 1e22feecc512381e042c708006ea4467663e74da..cab5ed593207529ca5ddd8a2ad8ddd9dda2b6f90 100644
--- a/lib/modules/datasource/npm/index.ts
+++ b/lib/modules/datasource/npm/index.ts
@@ -1,20 +1,18 @@
-import is from '@sindresorhus/is';
 import * as npmVersioning from '../../versioning/npm';
 import { Datasource } from '../datasource';
 import type { GetReleasesConfig, ReleaseResult } from '../types';
 import { id } from './common';
 import { getDependency } from './get';
-import { setNpmrc } from './npmrc';
 
 export { resetMemCache, resetCache } from './get';
 export { setNpmrc } from './npmrc';
 
-export const customRegistrySupport = false;
-
 export class NpmDatasource extends Datasource {
   static readonly id = id;
 
-  override readonly customRegistrySupport = false;
+  override readonly customRegistrySupport = true;
+
+  override readonly registryStrategy = 'first';
 
   override readonly defaultVersioning = npmVersioning.id;
 
@@ -24,12 +22,9 @@ export class NpmDatasource extends Datasource {
 
   async getReleases({
     packageName,
-    npmrc,
+    registryUrl,
   }: GetReleasesConfig): Promise<ReleaseResult | null> {
-    if (is.string(npmrc)) {
-      setNpmrc(npmrc);
-    }
-    const res = await getDependency(this.http, packageName);
+    const res = await getDependency(this.http, registryUrl, packageName);
     if (res) {
       res.tags = res['dist-tags'];
       delete res['dist-tags'];
diff --git a/lib/modules/datasource/npm/npmrc.ts b/lib/modules/datasource/npm/npmrc.ts
index c542a45cf850ee03878d06167a4415bff2d156fd..b18cf8242d432a0dae606038af4f10cc52fb4464 100644
--- a/lib/modules/datasource/npm/npmrc.ts
+++ b/lib/modules/datasource/npm/npmrc.ts
@@ -10,7 +10,7 @@ import { regEx } from '../../../util/regex';
 import { fromBase64 } from '../../../util/string';
 import { ensureTrailingSlash, validateUrl } from '../../../util/url';
 import { defaultRegistryUrls } from './common';
-import type { NpmrcRules, PackageResolution } from './types';
+import type { NpmrcRules } from './types';
 
 let npmrc: Record<string, any> = {};
 let npmrcRaw = '';
@@ -179,11 +179,12 @@ export function resolveRegistryUrl(packageName: string): string {
   return registryUrl;
 }
 
-export function resolvePackage(packageName: string): PackageResolution {
-  const registryUrl = resolveRegistryUrl(packageName);
-  const packageUrl = url.resolve(
+export function resolvePackageUrl(
+  registryUrl: string,
+  packageName: string
+): string {
+  return url.resolve(
     ensureTrailingSlash(registryUrl),
     encodeURIComponent(packageName).replace(regEx(/^%40/), '@')
   );
-  return { packageUrl, registryUrl };
 }
diff --git a/lib/modules/datasource/npm/types.ts b/lib/modules/datasource/npm/types.ts
index ac79e35562f36abdc061ee3f555014d944224bb2..10b600a75b0e3924456101f889e2e2e38dc5dd0f 100644
--- a/lib/modules/datasource/npm/types.ts
+++ b/lib/modules/datasource/npm/types.ts
@@ -47,8 +47,3 @@ export interface NpmDependency extends ReleaseResult {
 }
 
 export type Npmrc = Record<string, any>;
-
-export interface PackageResolution {
-  packageUrl: string;
-  registryUrl: string;
-}
diff --git a/lib/modules/datasource/types.ts b/lib/modules/datasource/types.ts
index 98362b3ec7059fffb551f165c5952beeee708205..318835e8ae6b09aa144a828997465dc46ca471a6 100644
--- a/lib/modules/datasource/types.ts
+++ b/lib/modules/datasource/types.ts
@@ -18,7 +18,6 @@ export interface DigestConfig {
 }
 
 export interface GetReleasesConfig {
-  npmrc?: string;
   packageName: string;
   registryUrl?: string;
 }