Skip to content
Latchkey

TypeScript "paths"/"baseUrl" Alias Not Resolving - Fix tsconfig in CI

A paths alias (@/*) that works in your editor can fail in CI when baseUrl is missing, when paths are defined in a base tsconfig that the project does not correctly extend, or when the bundler/runtime has no matching alias of its own.

What this error means

tsc reports TS2307: Cannot find module '@/...' in CI even though the editor resolves it, or the type-check passes but the runtime/bundler fails on the same alias. It is deterministic and tied to config inheritance.

tsc output
src/app/page.tsx:2:20 - error TS2307: Cannot find module '@/lib/api' or
its corresponding type declarations.

2 import { api } from '@/lib/api'
                       ~~~~~~~~~~~

Diagnose it: which tsconfig and which compiler?

A TypeScript error that appears only in CI usually means the runner is compiling with a different config or a different compiler version than your editor. Your editor uses the workspace TypeScript and the nearest tsconfig.json; CI uses whatever the lockfile resolved and whatever config the build script names.

Terminal
# what CI will actually use
npx tsc --version
npx tsc --showConfig | head -40

# which files are in the program (a missing include is a common cause)
npx tsc --listFiles | wc -l

# type-check only, no emit, same as most CI gates
npx tsc --noEmit

Common causes

baseUrl missing or paths not inherited

Older TypeScript requires baseUrl for paths to resolve. If paths live in an extended base config, the relative resolution can break unless the extending project re-declares them or uses the right relative roots.

Bundler/runtime lacks the matching alias

tsc paths only teach the type-checker. The bundler (Webpack resolve.alias, Vite resolve.alias) or Node runtime needs its own alias, or the alias resolves at type-check time but fails at build/run time.

How to fix it

Declare baseUrl and paths in the project tsconfig

Define both so resolution does not depend on inheritance quirks.

tsconfig.json
// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": { "@/*": ["src/*"] }
  }
}

Give the bundler the same alias

Mirror the tsconfig alias in the bundler (or derive it) so build/runtime resolution matches.

vite.config.ts
// vite.config.ts (or use vite-tsconfig-paths to derive from tsconfig)
resolve: { alias: { '@': '/src' } }

Pin the compiler so unrelated updates cannot break the gate

TypeScript adds errors in minor releases. An unpinned compiler turns a routine dependency update into a red build on code nobody touched, which is the most common false alarm in a TypeScript CI pipeline.

package.json
// package.json
{
  "devDependencies": {
    "typescript": "5.6.3"   // exact, not ^5.6.3
  }
}

How to prevent it

  • Declare baseUrl + paths in the project tsconfig, not only a base config.
  • Keep bundler/runtime aliases in sync with tsconfig paths (or derive them).
  • Run tsc --noEmit and the real build in CI so editor-only resolution gaps fail.

Frequently asked questions

What causes TypeScript "paths"/"baseUrl" alias not resolving?
There are 2 common causes: baseurl missing or paths not inherited and bundler/runtime lacks the matching alias. Older TypeScript requires baseUrl for paths to resolve.
How do I fix TypeScript "paths"/"baseUrl" alias not resolving?
There are 2 fixes depending on which cause you have: declare baseurl and paths in the project tsconfig and give the bundler the same alias. Work through them in order, since the first is the most common.
What does TypeScript "paths"/"baseUrl" alias not resolving actually mean?
tsc reports TS2307: Cannot find module '@/...' in CI even though the editor resolves it, or the type-check passes but the runtime/bundler fails on the same alias.
How do I stop TypeScript "paths"/"baseUrl" alias not resolving happening again?
Declare baseUrl + paths in the project tsconfig, not only a base config. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card