Using import.meta.url for Relative Paths in ES Modules

In modern JavaScript ECMAScript Modules (ESM), import.meta.url provides the absolute URL of the currently executing module file. By combining this property with the standard URL constructor, developers can reliably resolve relative asset paths—such as images, worker scripts, and JSON data—relative to the location of the module itself rather than the current working directory or the base HTML document.

What is import.meta.url?

import.meta is a host-populated object available in all JavaScript ES modules. Its url property returns a string containing the full URL of the current module.

Depending on the runtime environment: - In a web browser, it returns the network URL (for example, https://example.com/scripts/utils.js). - In Node.js or Deno, it returns a local file URL scheme (for example, file:///path/to/project/scripts/utils.js).

How Relative Path Resolution Works

The standard way to resolve a relative path using import.meta.url is to pass the relative path and import.meta.url to the standard URL constructor:

const assetUrl = new URL('./assets/logo.png', import.meta.url);

The URL constructor accepts two arguments: 1. input: The target relative or absolute path. 2. base: The base URL against which the input is resolved.

When import.meta.url is used as the base, the constructor calculates the final location using standard URL resolution rules:

The resulting URL object includes properties like .href (the full resolved URL string) and .pathname (the file path without the origin).

Common Use Cases

1. Loading Static Assets in the Browser

const image = new Image();
image.src = new URL('./images/icon.svg', import.meta.url).href;
document.body.appendChild(image);

2. Spawning Web Workers

Bundlers and modern browsers recognize worker instantiation when written with import.meta.url:

const worker = new Worker(
  new URL('./worker.js', import.meta.url),
  { type: 'module' }
);

3. File System Operations in Node.js

Because Node.js ES modules do not provide __dirname or __filename, import.meta.url is used alongside the node:url module to read local files:

import fs from 'node:fs/promises';
import { fileURLToPath } from 'node:url';

const filePath = fileURLToPath(new URL('./data.json', import.meta.url));
const fileData = await fs.readFile(filePath, 'utf-8');

Bundler Integration

Modern build tools like Vite, Webpack, and Rollup analyze new URL('...', import.meta.url) syntax statically during the build process. When detected, the bundler copies the referenced asset to the distribution folder, processes it (including hashing for cache busting), and updates the resolved URL to match the final production output path automatically.