diff --git a/OPTIONS.md b/OPTIONS.md
index 6ef5ce2d1..45e1d3fe7 100644
--- a/OPTIONS.md
+++ b/OPTIONS.md
@@ -20,7 +20,8 @@
   "${workspaceFolder}/**/*.js",
   "!**/node_modules/**"
 ]</pre></code><h4>outputCapture</h4><p>From where to capture output messages: the default debug API if set to <code>console</code>, or stdout/stderr streams if set to <code>std</code>.</p>
-<h5>Default value:</h4><pre><code>"console"</pre></code><h4>pauseForSourceMap</h4><p>Whether to wait for source maps to load for each incoming script. This has a performance overhead, and might be safely disabled when running off of disk, so long as <code>rootPath</code> is not disabled.</p>
+<h5>Default value:</h4><pre><code>"console"</pre></code><h4>pathMapping</h4><p>A mapping of folders from one path to another. To resolve scripts to their original locations. Typical use is to map scripts in <code>node_modules</code> to their sources that locate in another folder.</p>
+<h5>Default value:</h4><pre><code>{}</pre></code><h4>pauseForSourceMap</h4><p>Whether to wait for source maps to load for each incoming script. This has a performance overhead, and might be safely disabled when running off of disk, so long as <code>rootPath</code> is not disabled.</p>
 <h5>Default value:</h4><pre><code>false</pre></code><h4>port</h4><p>Debug port to attach to. Default is 9229.</p>
 <h5>Default value:</h4><pre><code>9229</pre></code><h4>processId</h4><p>ID of process to attach to.</p>
 <h5>Default value:</h4><pre><code>undefined</pre></code><h4>remoteRoot</h4><p>Absolute path to the remote directory containing the program.</p>
@@ -68,7 +69,8 @@
   "${workspaceFolder}/**/*.js",
   "!**/node_modules/**"
 ]</pre></code><h4>outputCapture</h4><p>From where to capture output messages: the default debug API if set to <code>console</code>, or stdout/stderr streams if set to <code>std</code>.</p>
-<h5>Default value:</h4><pre><code>"console"</pre></code><h4>pauseForSourceMap</h4><p>Whether to wait for source maps to load for each incoming script. This has a performance overhead, and might be safely disabled when running off of disk, so long as <code>rootPath</code> is not disabled.</p>
+<h5>Default value:</h4><pre><code>"console"</pre></code><h4>pathMapping</h4><p>A mapping of folders from one path to another. To resolve scripts to their original locations. Typical use is to map scripts in <code>node_modules</code> to their sources that locate in another folder.</p>
+<h5>Default value:</h4><pre><code>{}</pre></code><h4>pauseForSourceMap</h4><p>Whether to wait for source maps to load for each incoming script. This has a performance overhead, and might be safely disabled when running off of disk, so long as <code>rootPath</code> is not disabled.</p>
 <h5>Default value:</h4><pre><code>false</pre></code><h4>profileStartup</h4><p>If true, will start profiling as soon as the process launches</p>
 <h5>Default value:</h4><pre><code>false</pre></code><h4>program</h4><p>Absolute path to the program. Generated value is guessed by looking at package.json and opened files. Edit this attribute.</p>
 <h5>Default value:</h4><pre><code>""</pre></code><h4>remoteRoot</h4><p>Absolute path to the remote directory containing the program.</p>
@@ -116,7 +118,8 @@
   "${workspaceFolder}/**/*.js",
   "!**/node_modules/**"
 ]</pre></code><h4>outputCapture</h4><p>From where to capture output messages: the default debug API if set to <code>console</code>, or stdout/stderr streams if set to <code>std</code>.</p>
-<h5>Default value:</h4><pre><code>"console"</pre></code><h4>pauseForSourceMap</h4><p>Whether to wait for source maps to load for each incoming script. This has a performance overhead, and might be safely disabled when running off of disk, so long as <code>rootPath</code> is not disabled.</p>
+<h5>Default value:</h4><pre><code>"console"</pre></code><h4>pathMapping</h4><p>A mapping of folders from one path to another. To resolve scripts to their original locations. Typical use is to map scripts in <code>node_modules</code> to their sources that locate in another folder.</p>
+<h5>Default value:</h4><pre><code>{}</pre></code><h4>pauseForSourceMap</h4><p>Whether to wait for source maps to load for each incoming script. This has a performance overhead, and might be safely disabled when running off of disk, so long as <code>rootPath</code> is not disabled.</p>
 <h5>Default value:</h4><pre><code>false</pre></code><h4>remoteRoot</h4><p>Absolute path to the remote directory containing the program.</p>
 <h5>Default value:</h4><pre><code>null</pre></code><h4>resolveSourceMapLocations</h4><p>A list of minimatch patterns for locations (folders and URLs) in which source maps can be used to resolve local files. This can be used to avoid incorrectly breaking in external source mapped code. Patterns can be prefixed with &quot;!&quot; to exclude them. May be set to an empty array or null to avoid restriction.</p>
 <h5>Default value:</h4><pre><code>[
@@ -162,7 +165,8 @@
 <h5>Default value:</h4><pre><code>[
   "${workspaceFolder}/out/**/*.js"
 ]</pre></code><h4>outputCapture</h4><p>From where to capture output messages: the default debug API if set to <code>console</code>, or stdout/stderr streams if set to <code>std</code>.</p>
-<h5>Default value:</h4><pre><code>"console"</pre></code><h4>pauseForSourceMap</h4><p>Whether to wait for source maps to load for each incoming script. This has a performance overhead, and might be safely disabled when running off of disk, so long as <code>rootPath</code> is not disabled.</p>
+<h5>Default value:</h4><pre><code>"console"</pre></code><h4>pathMapping</h4><p>A mapping of folders from one path to another. To resolve scripts to their original locations. Typical use is to map scripts in <code>node_modules</code> to their sources that locate in another folder.</p>
+<h5>Default value:</h4><pre><code>{}</pre></code><h4>pauseForSourceMap</h4><p>Whether to wait for source maps to load for each incoming script. This has a performance overhead, and might be safely disabled when running off of disk, so long as <code>rootPath</code> is not disabled.</p>
 <h5>Default value:</h4><pre><code>false</pre></code><h4>remoteRoot</h4><p>Absolute path to the remote directory containing the program.</p>
 <h5>Default value:</h4><pre><code>null</pre></code><h4>rendererDebugOptions</h4><p>Chrome launch options used when attaching to the renderer process, with <code>debugWebviews</code> or <code>debugWebWorkerHost</code>.</p>
 <h5>Default value:</h4><pre><code>{}</pre></code><h4>resolveSourceMapLocations</h4><p>A list of minimatch patterns for locations (folders and URLs) in which source maps can be used to resolve local files. This can be used to avoid incorrectly breaking in external source mapped code. Patterns can be prefixed with &quot;!&quot; to exclude them. May be set to an empty array or null to avoid restriction.</p>
diff --git a/src/adapter/breakpointPredictor.ts b/src/adapter/breakpointPredictor.ts
index f35f9b399..c2b9d21f2 100644
--- a/src/adapter/breakpointPredictor.ts
+++ b/src/adapter/breakpointPredictor.ts
@@ -16,7 +16,7 @@ import { ISearchStrategy } from '../common/sourceMaps/sourceMapRepository';
 import { ISourcePathResolver } from '../common/sourcePathResolver';
 import { getOptimalCompiledPosition } from '../common/sourceUtils';
 import * as urlUtils from '../common/urlUtils';
-import { AnyLaunchConfiguration } from '../configuration';
+import { AnyLaunchConfiguration, PathMapping } from '../configuration';
 import Dap from '../dap/api';
 import { logPerf } from '../telemetry/performance';
 
@@ -26,7 +26,12 @@ export interface IWorkspaceLocation {
   columnNumber: number; // 1-based
 }
 
-type DiscoveredMetadata = ISourceMapMetadata & { sourceUrl: string; resolvedPath: string };
+type DiscoveredMetadata = ISourceMapMetadata & {
+  sourceUrl: string;
+  resolvedPath: string;
+  // is the meta for source map or path map
+  type: 'source' | 'path';
+};
 type MetadataMap = Map<string, Set<DiscoveredMetadata>>;
 
 const longPredictionWarning = 10 * 1000;
@@ -162,6 +167,7 @@ export class BreakpointsPredictor implements IBreakpointsPredictor {
   private readonly longParseEmitter = new EventEmitter<void>();
   private sourcePathToCompiled?: Promise<MetadataMap>;
   private cache?: CorrelatedCache<number, { sourceUrl: string; resolvedPath: string }[]>;
+  private readonly pathMapping: PathMapping;
 
   /**
    * Event that fires if it takes a long time to predict sourcemaps.
@@ -182,6 +188,8 @@ export class BreakpointsPredictor implements IBreakpointsPredictor {
         path.join(launchConfig.__workspaceCachePath, 'bp-predict.json'),
       );
     }
+
+    this.pathMapping = launchConfig.pathMapping;
   }
 
   private async createInitialMapping(): Promise<MetadataMap> {
@@ -218,8 +226,9 @@ export class BreakpointsPredictor implements IBreakpointsPredictor {
     try {
       await this.repo.streamChildrenWithSourcemaps(this.outFiles, async metadata => {
         const cached = await this.cache?.lookup(metadata.compiledPath, metadata.mtime);
+
         if (cached) {
-          cached.forEach(c => addDiscovery({ ...c, ...metadata }));
+          cached.forEach(c => addDiscovery({ ...c, ...metadata, type: 'source' }));
           return;
         }
 
@@ -240,7 +249,12 @@ export class BreakpointsPredictor implements IBreakpointsPredictor {
             continue;
           }
 
-          const discovery = { ...metadata, resolvedPath, sourceUrl: url };
+          const discovery: DiscoveredMetadata = {
+            ...metadata,
+            resolvedPath,
+            sourceUrl: url,
+            type: 'source',
+          };
           discovered.push(discovery);
           addDiscovery(discovery);
         }
@@ -255,6 +269,40 @@ export class BreakpointsPredictor implements IBreakpointsPredictor {
       this.logger.warn(LogTag.RuntimeException, 'Error reading sourcemaps from disk', { error });
     }
 
+    // search for files that path mapping affects, and add break point predictions for them
+    // if they don't have source mapping data
+    if (this.pathMapping && Object.keys(this.pathMapping).length > 0) {
+      await this.repo.streamChildrenWithPathMaps(
+        this.pathMapping,
+        async metadata => {
+          const cached = await this.cache?.lookup(metadata.compiledPath, -1);
+          if (cached) {
+            cached.forEach(c => addDiscovery({ ...c, ...metadata, type: 'path' }));
+            return;
+          }
+
+          const sourceMapped = await this.cache?.lookup(metadata.compiledPath);
+
+          // If a file that has sourcemap meta info, then use that for breakpoint prediction, and not
+          // the path map info
+          if (!sourceMapped) {
+            const sourceUrl = path.relative(metadata.compiledPath, metadata.sourceMapUrl);
+            addDiscovery({
+              compiledPath: metadata.compiledPath,
+              resolvedPath: metadata.sourceMapUrl,
+              sourceUrl,
+              sourceMapUrl: '',
+              type: 'path',
+            });
+          }
+        },
+        // search for normal .js files and node's ES6 module .mjs
+        // other extensions like .ts etc should have sourcemap info and should not
+        // be subjected to breakpoint prediction with path maps.
+        '**/*.{js,mjs}',
+      );
+    }
+
     clearTimeout(warnLongRuntime);
     return sourcePathToCompiled;
   }
@@ -288,14 +336,20 @@ export class BreakpointsPredictor implements IBreakpointsPredictor {
       return;
     }
 
-    const sourceMaps = await Promise.all(
-      [...set].map(metadata =>
-        this.sourceMapFactory
-          .load(metadata)
-          .then(map => ({ map, metadata }))
-          .catch(() => undefined),
-      ),
-    );
+    const byPathMap = [...set].filter(s => s.type === 'path');
+
+    const bySourceMap = [...set].filter(s => s.type === 'source');
+    const sourceMaps =
+      bySourceMap.length > 0
+        ? await Promise.all(
+            bySourceMap.map(metadata =>
+              this.sourceMapFactory
+                .load(metadata)
+                .then(map => ({ map, metadata }))
+                .catch(() => undefined),
+            ),
+          )
+        : [];
 
     for (const b of params.breakpoints ?? []) {
       const key = `${params.source.path}:${b.line}:${b.column || 1}`;
@@ -306,6 +360,14 @@ export class BreakpointsPredictor implements IBreakpointsPredictor {
       const locations: IWorkspaceLocation[] = [];
       this.predictedLocations.set(key, locations);
 
+      for (const pathMapMeta of byPathMap) {
+        locations.push({
+          absolutePath: pathMapMeta.compiledPath,
+          lineNumber: b.line,
+          columnNumber: b.column || 1,
+        });
+      }
+
       for (const sourceMapLoad of sourceMaps) {
         if (!sourceMapLoad) {
           continue;
diff --git a/src/build/generate-contributions.ts b/src/build/generate-contributions.ts
index 67b040fcc..1f3eea779 100644
--- a/src/build/generate-contributions.ts
+++ b/src/build/generate-contributions.ts
@@ -298,6 +298,12 @@ const baseConfigurationAttributes: ConfigurationAttributes<IBaseConfiguration> =
     default: [],
     description: refString('base.cascadeTerminateToConfigurations.label'),
   },
+  pathMapping: {
+    type: 'object',
+    additionalProperties: { type: 'string' },
+    description: refString('browser.pathMapping.description'),
+    default: {},
+  },
 };
 
 /**
@@ -357,6 +363,10 @@ const nodeBaseConfigurationAttributes: ConfigurationAttributes<INodeBaseConfigur
     description: refString('node.versionHint.description'),
     default: 12,
   },
+  pathMapping: {
+    ...baseConfigurationAttributes.pathMapping,
+    markdownDescription: refString('node.pathMapping.description'),
+  },
 };
 
 /**
@@ -679,9 +689,8 @@ const chromiumBaseConfigurationAttributes: ConfigurationAttributes<IChromiumBase
     default: true,
   },
   pathMapping: {
-    type: 'object',
+    ...baseConfigurationAttributes.pathMapping,
     description: refString('browser.pathMapping.description'),
-    default: {},
   },
   webRoot: {
     type: 'string',
diff --git a/src/build/strings.ts b/src/build/strings.ts
index c75ad8a6b..8be0d67fb 100644
--- a/src/build/strings.ts
+++ b/src/build/strings.ts
@@ -225,6 +225,8 @@ const strings = {
   'node.sourceMapPathOverrides.description':
     'A set of mappings for rewriting the locations of source files from what the sourcemap says, to their locations on disk.',
   'node.sourceMaps.description': 'Use JavaScript source maps (if they exist).',
+  'node.pathMapping.description':
+    'A mapping of folders from one path to another. To resolve scripts to their original locations. Typical use is to map scripts in `node_modules` to their sources that locate in another folder.',
   'node.stopOnEntry.description': 'Automatically stop program after launch.',
   'node.timeout.description':
     'Retry for this number of milliseconds to connect to Node.js. Default is 10000 ms.',
diff --git a/src/common/sourceMaps/codeSearchStrategy.ts b/src/common/sourceMaps/codeSearchStrategy.ts
index be48a3050..2f6d26bd5 100644
--- a/src/common/sourceMaps/codeSearchStrategy.ts
+++ b/src/common/sourceMaps/codeSearchStrategy.ts
@@ -2,14 +2,15 @@
  * Copyright (C) Microsoft Corporation. All rights reserved.
  *--------------------------------------------------------*/
 
+import { injectable } from 'inversify';
 import type * as vscodeType from 'vscode';
-import { LogTag, ILogger } from '../logging';
+import { PathMapping } from '../../configuration';
+import { FileGlobList } from '../fileGlobList';
+import { ILogger, LogTag } from '../logging';
 import { forceForwardSlashes } from '../pathUtils';
 import { NodeSearchStrategy } from './nodeSearchStrategy';
 import { ISourceMapMetadata } from './sourceMap';
 import { createMetadataForFile, ISearchStrategy } from './sourceMapRepository';
-import { injectable } from 'inversify';
-import { FileGlobList } from '../fileGlobList';
 
 /**
  * A source map repository that uses VS Code's proposed search API to
@@ -46,6 +47,37 @@ export class CodeSearchStrategy implements ISearchStrategy {
     return this.nodeStrategy.streamAllChildren(files, onChild);
   }
 
+  /**
+   * @inheritdoc
+   */
+  public async streamChildrenWithPathMaps<T>(
+    pathMapping: PathMapping,
+    onChild: (child: Required<ISourceMapMetadata>) => Promise<T>,
+    pattern = '**',
+  ): Promise<T[]> {
+    const todo: Promise<T>[] = [];
+
+    // process pathMapping config
+    const mappedPaths = Object.keys(pathMapping);
+    for (const path of mappedPaths) {
+      const files = await this.vscode.workspace.findFiles(
+        new this.vscode.RelativePattern(path, pattern),
+      );
+      for (const file of files) {
+        const sourceMapUrl = file.path.replace(path, pathMapping[path]);
+        todo.push(
+          onChild({
+            compiledPath: file.path,
+            mtime: -1,
+            sourceMapUrl,
+          }),
+        );
+      }
+    }
+
+    return (await Promise.all(todo)).filter((t): t is T => t !== undefined);
+  }
+
   /**
    * @inheritdoc
    */
diff --git a/src/common/sourceMaps/mtimeCorrelatedCache.ts b/src/common/sourceMaps/mtimeCorrelatedCache.ts
index 782efc42c..603e8a2e0 100644
--- a/src/common/sourceMaps/mtimeCorrelatedCache.ts
+++ b/src/common/sourceMaps/mtimeCorrelatedCache.ts
@@ -3,9 +3,9 @@
  *--------------------------------------------------------*/
 import { mkdirSync } from 'fs';
 import { dirname } from 'path';
-import { debounce } from '../objUtils';
 import { IDisposable } from '../disposable';
 import { readfile, writeFile } from '../fsUtils';
+import { debounce } from '../objUtils';
 
 export class CorrelatedCache<C, V> implements IDisposable {
   private cacheData?: Promise<{ [key: string]: { correlation: C; value: V } }>;
@@ -26,10 +26,12 @@ export class CorrelatedCache<C, V> implements IDisposable {
   /**
    * Gets the value from the map if it exists and the correlation matches.
    */
-  public async lookup(key: string, correlation: C): Promise<V | undefined> {
+  public async lookup(key: string, correlation?: C): Promise<V | undefined> {
     const data = await this.getData();
     const entry = data[key];
-    return entry && entry.correlation === correlation ? entry.value : undefined;
+    return entry && (correlation === undefined || entry.correlation === correlation)
+      ? entry.value
+      : undefined;
   }
 
   /**
diff --git a/src/common/sourceMaps/nodeSearchStrategy.ts b/src/common/sourceMaps/nodeSearchStrategy.ts
index 54bd8710c..fe2a2c58c 100644
--- a/src/common/sourceMaps/nodeSearchStrategy.ts
+++ b/src/common/sourceMaps/nodeSearchStrategy.ts
@@ -2,14 +2,14 @@
  * Copyright (C) Microsoft Corporation. All rights reserved.
  *--------------------------------------------------------*/
 
-import { ISourceMapMetadata } from './sourceMap';
-import { ISearchStrategy, createMetadataForFile } from './sourceMapRepository';
 import globStream from 'glob-stream';
-import { LogTag, ILogger } from '../logging';
-import { forceForwardSlashes, fixDriveLetterAndSlashes } from '../pathUtils';
-import { injectable, inject } from 'inversify';
+import { inject, injectable } from 'inversify';
+import { PathMapping } from '../../configuration';
 import { FileGlobList } from '../fileGlobList';
-
+import { ILogger, LogTag } from '../logging';
+import { fixDriveLetterAndSlashes, forceForwardSlashes } from '../pathUtils';
+import { ISourceMapMetadata } from './sourceMap';
+import { createMetadataForFile, ISearchStrategy } from './sourceMapRepository';
 /**
  * A source map repository that uses globbing to find candidate files.
  */
@@ -38,6 +38,16 @@ export class NodeSearchStrategy implements ISearchStrategy {
     return (await Promise.all(todo)).filter((t): t is T => t !== undefined);
   }
 
+  /**
+   * @inheritdoc
+   */
+  public async streamChildrenWithPathMaps<T>(
+    _pathMapping: PathMapping,
+    _onChild: (child: Required<ISourceMapMetadata>) => T | Promise<T>,
+  ): Promise<T[]> {
+    return Promise.resolve([]);
+  }
+
   /**
    * @inheritdoc
    */
diff --git a/src/common/sourceMaps/sourceMapRepository.ts b/src/common/sourceMaps/sourceMapRepository.ts
index cfd0b3a03..e5c1a0a96 100644
--- a/src/common/sourceMaps/sourceMapRepository.ts
+++ b/src/common/sourceMaps/sourceMapRepository.ts
@@ -2,6 +2,7 @@
  * Copyright (C) Microsoft Corporation. All rights reserved.
  *--------------------------------------------------------*/
 
+import { PathMapping } from '../../configuration';
 import { FileGlobList } from '../fileGlobList';
 import { readfile, stat } from '../fsUtils';
 import { parseSourceMappingUrl } from '../sourceUtils';
@@ -29,6 +30,17 @@ export interface ISearchStrategy {
     onChild: (child: Required<ISourceMapMetadata>) => T | Promise<T>,
   ): Promise<T[]>;
 
+  /**
+   * Recursively finds all children that match the pathMap setting, calling
+   * `onChild` when children are found and returning promise that resolves
+   * once all children have been discovered.
+   */
+  streamChildrenWithPathMaps<T>(
+    pathMapping: PathMapping,
+    onChild: (child: Required<ISourceMapMetadata>) => T | Promise<T>,
+    pattern?: string,
+  ): Promise<T[]>;
+
   /**
    * Recursively finds all children, calling `onChild` when children are found
    * and returning promise that resolves once all children have been discovered.
diff --git a/src/configuration.ts b/src/configuration.ts
index 5dd5ddd36..7e67cd8e6 100644
--- a/src/configuration.ts
+++ b/src/configuration.ts
@@ -207,6 +207,14 @@ export interface IBaseConfiguration extends IMandatedConfiguration {
    * e.g.: "function () { return {...this, extraProperty: 'otherProperty' } }"
    */
   customPropertiesGenerator?: string;
+
+  /**
+   * A mapping of folder paths. In the context of Chrome, these are "path"
+   * portions of the URL to absolute paths on disk. In the context of
+   * Node.js, they are mappings from absolute paths to other absolute paths,
+   * which is useful when debugging hard linked files.
+   */
+  pathMapping: PathMapping;
 }
 
 export interface IExtensionHostBaseConfiguration extends INodeBaseConfiguration {
@@ -420,7 +428,7 @@ export interface INodeLaunchConfiguration extends INodeBaseConfiguration, IConfi
   attachSimplePort: null | number;
 
   /**
-   * Configures how debug process are killed when stopping the sesssion. Can be:
+   * Configures how debug process are killed when stopping the session. Can be:
    *  - forceful (default): forcefully tears down the process tree. Sends
    *    SIGKILL on posix, or `taskkill.exe /F` on Windows.
    *  - polite: gracefully tears down the process tree. It's possible that
@@ -443,12 +451,6 @@ export interface IChromiumBaseConfiguration extends IBaseConfiguration {
    */
   disableNetworkCache: boolean;
 
-  /**
-   * A mapping of URLs/paths to local folders, to resolve scripts
-   * in Chrome to scripts on disk
-   */
-  pathMapping: PathMapping;
-
   /**
    * This specifies the workspace absolute path to the webserver root. Used to
    * resolve paths like `/app.js` to files on disk. Shorthand for a pathMapping for "/".
@@ -812,6 +814,7 @@ export const baseDefaults: IBaseConfiguration = {
   sourceMapPathOverrides: defaultSourceMapPathOverrides('${workspaceFolder}'),
   enableContentValidation: true,
   cascadeTerminateToConfigurations: [],
+  pathMapping: {},
   // Should always be determined upstream;
   __workspaceFolder: '',
   __autoExpandGetters: false,
@@ -893,7 +896,6 @@ export const chromeAttachConfigDefaults: IChromeAttachConfiguration = {
   address: 'localhost',
   port: 0,
   disableNetworkCache: true,
-  pathMapping: {},
   url: null,
   restart: false,
   urlFilter: '',
@@ -1068,6 +1070,10 @@ export function removeOptionalWorkspaceFolderUsages<T extends AnyLaunchConfigura
       cast.resolveSourceMapLocations?.filter(o => !o.includes(token)) ?? null;
   }
 
+  if ('pathMapping' in cast) {
+    cast.pathMapping = filterValues(cast.pathMapping, v => v.includes(token));
+  }
+
   if ('cwd' in cast && cast.cwd?.includes(token)) {
     cast.cwd = undefined;
   }
diff --git a/src/targets/browser/browserPathResolver.ts b/src/targets/browser/browserPathResolver.ts
index ae30a407f..05311e6b6 100644
--- a/src/targets/browser/browserPathResolver.ts
+++ b/src/targets/browser/browserPathResolver.ts
@@ -23,12 +23,10 @@ import {
 import { IUrlResolution } from '../../common/sourcePathResolver';
 import * as utils from '../../common/urlUtils';
 import { urlToRegex } from '../../common/urlUtils';
-import { PathMapping } from '../../configuration';
 import { ISourcePathResolverOptions, SourcePathResolverBase } from '../sourcePathResolver';
 
 export interface IOptions extends ISourcePathResolverOptions {
   baseUrl?: string;
-  pathMapping: PathMapping;
   clientID: string | undefined;
   remoteFilePrefix: string | undefined;
 }
diff --git a/src/targets/node/nodeSourcePathResolver.ts b/src/targets/node/nodeSourcePathResolver.ts
index 9b7978835..6bebcc9db 100644
--- a/src/targets/node/nodeSourcePathResolver.ts
+++ b/src/targets/node/nodeSourcePathResolver.ts
@@ -9,6 +9,7 @@ import { ILogger } from '../../common/logging';
 import { fixDriveLetterAndSlashes, properResolve } from '../../common/pathUtils';
 import { SourceMap } from '../../common/sourceMaps/sourceMap';
 import {
+  defaultPathMappingResolver,
   getComputedSourceRoot,
   getFullSourceEntry,
   moduleAwarePathMappingResolver,
@@ -26,6 +27,8 @@ interface IOptions extends ISourcePathResolverOptions {
 const localNodeInternalsPrefix = 'node:';
 
 export class NodeSourcePathResolver extends SourcePathResolverBase<IOptions> {
+  private hasPathMapping: boolean;
+
   public static shouldWarnAboutSymlinks(config: AnyLaunchConfiguration) {
     return 'runtimeArgs' in config && !config.runtimeArgs?.includes('--preserve-symlinks');
   }
@@ -37,6 +40,7 @@ export class NodeSourcePathResolver extends SourcePathResolverBase<IOptions> {
       sourceMapOverrides: c.sourceMapPathOverrides,
       remoteRoot: c.remoteRoot,
       localRoot: c.localRoot,
+      pathMapping: c.pathMapping,
     };
   }
 
@@ -47,6 +51,7 @@ export class NodeSourcePathResolver extends SourcePathResolverBase<IOptions> {
     protected readonly logger: ILogger,
   ) {
     super(options, logger);
+    this.hasPathMapping = Object.keys(this.options.pathMapping).length > 0;
   }
 
   /**
@@ -65,6 +70,30 @@ export class NodeSourcePathResolver extends SourcePathResolverBase<IOptions> {
     return this.options;
   }
 
+  /**
+   * map remote path to local path and apply the pathMapping option
+   *
+   * @param scriptPath remote path
+   * @returns mapped path
+   */
+  private async rebaseRemoteWithPathMapping(scriptPath: string): Promise<string> {
+    const mapped = this.rebaseRemoteToLocal(scriptPath);
+
+    if (this.hasPathMapping) {
+      const mapped2 = await defaultPathMappingResolver(
+        mapped,
+        this.options.pathMapping,
+        this.logger,
+      );
+
+      if (mapped2 && (await this.fsUtils.exists(mapped2))) {
+        return mapped2;
+      }
+    }
+
+    return mapped;
+  }
+
   /**
    * @override
    */
@@ -89,7 +118,7 @@ export class NodeSourcePathResolver extends SourcePathResolverBase<IOptions> {
 
     const absolutePath = urlUtils.fileUrlToAbsolutePath(url);
     if (absolutePath) {
-      return this.rebaseRemoteToLocal(absolutePath);
+      return await this.rebaseRemoteWithPathMapping(absolutePath);
     }
 
     // It's possible the source might be an HTTP if using the `sourceURL`
@@ -111,7 +140,7 @@ export class NodeSourcePathResolver extends SourcePathResolverBase<IOptions> {
     }
 
     const withBase = properResolve(this.options.basePath ?? '', url);
-    return this.rebaseRemoteToLocal(withBase);
+    return await this.rebaseRemoteWithPathMapping(withBase);
   }
 
   /**
@@ -175,6 +204,6 @@ export class NodeSourcePathResolver extends SourcePathResolverBase<IOptions> {
       );
     }
 
-    return this.rebaseRemoteToLocal(url) || url;
+    return await this.rebaseRemoteWithPathMapping(url);
   }
 }
diff --git a/src/targets/sourcePathResolver.ts b/src/targets/sourcePathResolver.ts
index 120eeb351..8c8fa7a86 100644
--- a/src/targets/sourcePathResolver.ts
+++ b/src/targets/sourcePathResolver.ts
@@ -25,9 +25,11 @@ import {
   urlToRegex,
 } from '../common/urlUtils';
 import { SourceMapOverrides } from './sourceMapOverrides';
+import { PathMapping } from '../configuration';
 
 export interface ISourcePathResolverOptions {
   resolveSourceMapLocations: ReadonlyArray<string> | null;
+  pathMapping: PathMapping;
   sourceMapOverrides: { [key: string]: string };
   localRoot: string | null;
   remoteRoot: string | null;
diff --git a/src/test/browser/browserPathResolverTest.ts b/src/test/browser/browserPathResolverTest.ts
index 856fb1127..3f3016259 100644
--- a/src/test/browser/browserPathResolverTest.ts
+++ b/src/test/browser/browserPathResolverTest.ts
@@ -99,6 +99,9 @@ describe('browserPathResolver.urlToAbsolutePath', () => {
           streamChildrenWithSourcemaps() {
             return Promise.resolve([]);
           },
+          streamChildrenWithPathMaps() {
+            return Promise.resolve([]);
+          },
           streamAllChildren(_files, onChild) {
             return Promise.all([
               onChild(path.join(testFixturesDir, 'web', 'a.vue')),
diff --git a/src/test/node/node-source-path-resolver.test.ts b/src/test/node/node-source-path-resolver.test.ts
index 79782f243..7f9007ef7 100644
--- a/src/test/node/node-source-path-resolver.test.ts
+++ b/src/test/node/node-source-path-resolver.test.ts
@@ -20,6 +20,7 @@ describe('node source path resolver', () => {
       remoteRoot: null,
       localRoot: null,
       sourceMapOverrides: { 'webpack:///*': `${__dirname}/*` },
+      pathMapping: {},
     };
 
     it('resolves absolute', async () => {
@@ -95,6 +96,35 @@ describe('node source path resolver', () => {
       );
     });
 
+    it('applies pathMapping option', async () => {
+      const r = new NodeSourcePathResolver(
+        {
+          realPath: fsUtils.realPath,
+          readFile: fsUtils.readFile,
+          exists: async p => p === '/lib/index.js',
+        },
+        undefined,
+        {
+          ...defaultOptions,
+          pathMapping: {
+            '/src': '/lib',
+          },
+        },
+        Logger.null,
+      );
+
+      expect(await r.urlToAbsolutePath({ url: 'file:///src/index.js' })).to.equal('/lib/index.js');
+      expect(await r.urlToAbsolutePath({ url: 'file:///src/not-exist.js' })).to.equal(
+        '/src/not-exist.js',
+      );
+      expect(await r.urlToAbsolutePath({ url: 'file:///src2/index.js' })).to.equal(
+        '/src2/index.js',
+      );
+      expect(await r.urlToAbsolutePath({ url: 'file:///test/src/index.js' })).to.equal(
+        '/test/src/index.js',
+      );
+    });
+
     describe('source map filtering', () => {
       const testTable = {
         'matches paths': {