Skip to content

How to fix: javascript importing with absolute path

In JavaScript, an absolute path import (e.g., import { util } from "/src/utils/helper.js") often results in a Module not found error or a 404 (Not Found) in the browser.

The core issue is Resolution Context. By default, if a path starts with /, the environment (Node.js or the Browser) interprets this as the literal root of the filesystem or the server’s domain root. It does not automatically know that your “root” is actually the folder containing your package.json. To use absolute-style imports safely, you must configure a Module Alias or a Base URL.

Scenario Issue Common Error Message
Node.js Runtime Node attempts to resolve / from the OS root directory. Error [ERR_MODULE_NOT_FOUND]
Browser (Native ESM) The browser requests https://domain.com/src/... which doesn’t exist on the server. GET ... 404 (Not Found)
Build Tools (Vite/Webpack) The bundler doesn’t have an alias defined for the project root. [vite] Internal server error: Failed to resolve import
TypeScript/VS Code The IntelliSense engine cannot map the path to the local disk. Cannot find module or its corresponding type declarations.

1. The Modern Node.js Way (Subpath Imports)

Section titled “1. The Modern Node.js Way (Subpath Imports)”

If you are using Node.js 14.19+ or 16+, you can define “imports” in your package.json. This is the native way to achieve absolute-like imports using a prefix (usually #).

{
"name": "my-project",
"type": "module",
"imports": {
"#utils/*.js": "./src/utils/*.js"
}
}

Usage:

// This resolves to ./src/utils/validator.js
import { validate } from "#utils/validator.js";

Vite uses alias to map a specific character (like @) to your project’s source directory.

vite.config.js
import { defineConfig } from 'vite';
import path from 'path';
export default defineConfig({
resolve: {
alias: {
// Map "@" to the "src" directory
'@': path.resolve(__dirname, './src'),
},
},
});

Usage:

import { Header } from '@/components/Header';

If you are using a custom Webpack setup (or an older React project), use the resolve.alias property.

webpack.config.js
const path = require('path');
module.exports = {
// ...
resolve: {
alias: {
Components: path.resolve(__dirname, 'src/components/'),
Utils: path.resolve(__dirname, 'src/utils/'),
},
},
};

4. Fixing IDE Support (jsconfig.json / tsconfig.json)

Section titled “4. Fixing IDE Support (jsconfig.json / tsconfig.json)”

Even if your code runs, your IDE might show red squiggly lines. You must tell the editor how to resolve the paths.

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

Note: Press Ctrl + Shift + P in VS Code and run “Developer: Reload Window” after changing this file.

  1. Prefer Aliasing over Literal Absolute Paths: Avoid using raw /src/... imports. Use a prefix like @/ or ~ to explicitly signal that the path is an alias. This prevents confusion with OS-level absolute paths.
  2. Sync Configs: Ensure your vite.config.js / webpack.config.js aliases match your tsconfig.json paths exactly. Discrepancies lead to code that “builds but shows errors” or vice versa.
  3. Use Directory Indexes: Use index.js files in folders to keep import statements clean:
    • Bad: import { x } from '@/features/users/components/UserList.js'
    • Good: import { UserList } from '@/features/users'
  4. Avoid Deep Nesting: If you find yourself needing ../../../../../, it’s a sign your architecture is too flat or too deep. Use aliases to flatten the resolution.