Skip to content

Path alias loading ignores extends — aliases in tsconfig.base.json (Nx-style monorepos) silently fail to resolve #1534

Description

@Easonliu841116

Summary

loadProjectAliases() only probes <projectRoot>/tsconfig.json and jsconfig.json, and does not follow extends chains — the header comment acknowledges this (src/resolution/path-aliases.ts):

 *   - does NOT follow `extends` chains yet (most projects don't need it)
const candidates = ['tsconfig.json', 'jsconfig.json'];

It is also called exactly once, at the repo root (src/resolution/index.ts:648):

this.projectAliases = loadProjectAliases(this.projectRoot);

Nx-style TypeScript monorepos keep all compilerOptions.paths entries in tsconfig.base.json. A root tsconfig.json frequently doesn't exist at all, and per-project tsconfig.json files just extends the base without defining their own paths. The package.json workspaces fallback doesn't help either — Nx repos typically don't declare workspaces there.

Impact

On our TS monorepo (~5,000 tracked source files, 28 paths entries in tsconfig.base.json), every cross-package import (from '@scope/lib-name') — files containing them are ~64% of the codebase — fails alias resolution. Those imports fall back to name-based matching, which is documented to attach edges to wrong same-named symbols (#1355, #1512), so impact/callers silently under- and over-report on exactly the queries a monorepo needs them for (blast radius of shared libs).

The silent part is what hurts: results come back precise-looking with no unresolved-import warning, and the MCP server instructions tell agents to trust the results without re-verifying.

Suggested fix

  1. Follow the extends chain when loading aliases (resolve relative refs, merge paths with nearest-wins semantics); or at minimum
  2. Add tsconfig.base.json to the candidate list at the workspace root — nx.json is already used as a root marker in src/directory.ts, so its presence could hint where to look.

Workaround considered

Duplicating the paths block into a root tsconfig.json works in principle, but it drifts from tsconfig.base.json over time, so we'd rather not ship that.

Version: v1.5.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions