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

Sarthak BatraSarthak Batra
3 min read

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

  1. Install @types/node (required for using path and __dirname in vite.config.ts):

    Bash

     npm install -D @types/node
    
  2. Copy the configurations above into your respective files (tsconfig.json, tsconfig.app.json, and vite.config.ts).

  3. Restart your development server:

    Bash

     npm run dev
    
  4. 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 (where tsconfig.json is located).

  • "@/*": ["src/*"]: This is the path mapping. It tells TypeScript that any import starting with @/ should be mapped to the src/ directory.

  • path.resolve(__dirname, './src'): This is used in vite.config.ts to create a reliable, absolute file path to your src 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!

0
Subscribe to my newsletter

Read articles from Sarthak Batra directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sarthak Batra
Sarthak Batra