Stop Wrestling with Relative Imports: Master Absolute Imports in React + TypeScript + Vite


Why Absolute Imports Matter
The difference is immediately clear.
Before (Relative Imports):
TypeScript
import Button from '../../../components/ui/Button'
import { useAuth } from '../../../../hooks/useAuth'
import logo from '../../assets/images/logo.svg'
After (Absolute Imports):
TypeScript
import Button from '@/components/ui/Button'
import { useAuth } from '@/hooks/useAuth'
import logo from '@/assets/images/logo.svg'
Benefits
No more path confusion when moving files.
Cleaner, more readable import statements.
Easier refactoring and file organization.
Consistent imports across your entire project.
The Complete Setup
To get absolute imports working, you need to tell both TypeScript (for type checking and autocompletion) and Vite (your bundler) how to resolve these new paths.
1. tsconfig.json
This is the root TypeScript config. We just need to ensure it references our other TypeScript configurations. The key settings for path aliases will go in tsconfig.app
.json
.
JSON
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
2. tsconfig.app
.json
This file configures TypeScript for your application code. Here we define the baseUrl
and paths
so that TypeScript understands the @
alias.
JSON
{
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2022",
"useDefineForClassFields": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Path Alias Configuration */
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
3. vite.config.ts
Finally, update your Vite configuration to resolve the path aliases during the build and development process.
TypeScript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
}
}
})
Quick Setup Steps
Install
@types/node
(required for usingpath
and__dirname
invite.config.ts
):Bash
npm install -D @types/node
Copy the configurations above into your respective files (
tsconfig.json
,tsconfig.app
.json
, andvite.config.ts
).Restart your development server:
Bash
npm run dev
Restart the TypeScript server in your IDE (In VS Code:
Cmd + Shift + P
→ "TypeScript: Restart TS Server").
Usage Examples
Now you can use clean, absolute paths everywhere in your project.
TypeScript
// Components
import Header from '@/components/Header'
import Button from '@/components/ui/Button'
// Assets
import logo from '@/assets/logo.svg'
import heroImage from '@/assets/images/hero.jpg'
// Utils & Hooks
import { formatDate } from '@/utils/date'
import { useAuth } from '@/hooks/useAuth'
Key Configuration Details
"baseUrl": "."
: This tells the TypeScript compiler that the root for path resolution is the project's root directory (wheretsconfig.json
is located)."@/*": ["src/*"]
: This is the path mapping. It tells TypeScript that any import starting with@/
should be mapped to thesrc/
directory.path.resolve(__dirname, './src')
: This is used invite.config.ts
to create a reliable, absolute file path to yoursrc
directory, ensuring Vite can find the files correctly regardless of the operating system.
Your imports are now cleaner, your code is more maintainable, and file reorganization is effortless. No more counting ../
levels!
Subscribe to my newsletter
Read articles from Sarthak Batra directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
