Path Aliases in TypeScript
Path aliases let you replace long relative import paths with short, meaningful names. Learn how to configure tsconfig paths, use wildcards, and avoid common pitfalls.
TypeScript path aliases let you replace long, fragile relative import paths with short, meaningful names. Instead of writing a path that chains through several parent directories, you can write a clean named reference. The mapping between the alias and the real file path lives in tsconfig.json.
Without aliases, every import navigates through the directory tree. Moving a file means updating every import that points to it.
With aliases, imports stay the same regardless of where files live. This is what the before and after looks like.
The unaliased version chains through parent directories:
import { formatDate } from "../../../shared/utils/format.js";
import { Button } from "../../components/Button.js";With path aliases configured, the same imports become clean and independent of file location. Each import reads like a named reference rather than directory navigation:
import { formatDate } from "@shared/utils/format.js";
import { Button } from "@components/Button.js";Configuring Path Aliases
Path aliases are configured in the paths compiler option inside tsconfig.json. Each alias maps a name prefix to one or more directory paths on disk.
The baseUrl tells TypeScript where to start resolving paths. When baseUrl is set to the project root, path values are relative to that root.
Since TypeScript 4.1, baseUrl is optional. If omitted, path values resolve relative to the tsconfig.json file itself.
After adding this configuration, TypeScript understands that an alias like @shared/utils/format means the corresponding file under src/shared. The compiler resolves imports using these aliases, checks types, and provides autocomplete as if you wrote the full relative path.
Wildcard Patterns
The asterisk in path aliases is a wildcard that matches any string. When TypeScript resolves an import, it replaces the matched portion with the corresponding path value.
This tsconfig maps the alias @features to a directory:
{
"compilerOptions": {
"paths": {
"@features/*": ["./src/features/*"]
}
}
}When you write an import of @features/auth, TypeScript matches the pattern, captures auth as the wildcard value, substitutes it into the target path, and resolves to the corresponding TypeScript file. You can use multiple wildcards in the same configuration, and more specific aliases take priority over general ones.
The Critical Pitfall: Paths Do Not Affect Emit
The paths compiler option only tells TypeScript how to resolve imports. It does not change the import paths in the compiled JavaScript files. This is the most important thing to understand about path aliases and the most common source of runtime crashes.
TypeScript compiles an aliased import into JavaScript that still contains the alias prefix. Node.js does not understand these custom prefixes. If you run this code without additional configuration, it crashes with a module not found error.
To make path aliases work at runtime, you must configure your bundler or runtime separately. For Vite, add resolve.alias to vite.config.ts. For Webpack, use resolve.alias in webpack.config.js with the same mappings.
For tsx or ts-node, use a tool like tsc-alias that rewrites alias paths in the compiled output.
The rule is simple: every alias in tsconfig paths must have a matching alias in your build configuration. Skip this step and the code fails at runtime even though TypeScript was perfectly happy.
When to Use Path Aliases
Path aliases are appropriate for application projects where you control the build pipeline. They reduce import noise, make refactoring easier, and give your project a clear namespace structure.
They are not appropriate for published npm libraries. If a library uses path aliases, every consumer must configure the same aliases in their own TypeScript and bundler settings. Libraries should use relative imports or package.json imports instead.
For more on library-safe alternatives, see module resolution in TypeScript. Path aliases are a convenience for application code, not a publishing mechanism.
Common Mistakes
Configuring paths without configuring the bundler. TypeScript resolves the alias, but the runtime crashes because it does not understand the alias prefix. Always mirror your path aliases in your build tool configuration.
Using paths to point into node_modules. Path aliases override normal package resolution. If you map a path to a node_modules package, TypeScript skips the package.json exports field and other package metadata. The resolved types may be wrong.
Forgetting file extensions with nodenext. When using moduleResolution nodenext, imports still need .js extensions even through aliases. Write the full path with the extension. For more on this rule, see ES modules in TypeScript.
Overusing aliases. A handful of well-chosen aliases make imports clearer. Dozens of aliases with single-file mappings create confusion and make the project harder to navigate.
Rune AI
Key Insights
- Path aliases replace long relative import paths with short names configured in tsconfig paths.
- Use wildcards like @app/* to map entire directories instead of individual files.
- Path aliases do not affect emitted JavaScript. You must configure your bundler separately.
- baseUrl is optional since TypeScript 4.1. Paths resolve relative to tsconfig.json by default.
- Never use path aliases in published libraries. Use package.json imports instead.
Frequently Asked Questions
Do path aliases change the emitted JavaScript import paths?
Can I use path aliases in a published npm library?
Is baseUrl required when using paths?
Conclusion
Path aliases make imports cleaner and easier to refactor by replacing long relative paths with short, meaningful names. Configure them in tsconfig paths, use wildcards for directory-level aliases, and always remember that paths do not change emitted JavaScript. Make sure your bundler or runtime mirrors the same aliases.
More in this topic
TypeScript Compiler Explained
The TypeScript compiler (tsc) turns .ts files into .js files while checking types. Learn what it does, how to use it, and how it fits your workflow.
Set Up ESLint for TypeScript
Install and configure ESLint with typescript-eslint to catch bugs and enforce consistent code style in your TypeScript project.
Pick Utility Type in TypeScript
Pick creates a new type by selecting only the properties you name from an existing type. Use it to build focused types for specific views, API responses, or function parameters.