Reference guide · html-css-js · Published 2026-08-16 · 3 min read

Import maps for JavaScript module resolution

Use an HTML import map to resolve bare JavaScript module specifiers natively. Import npm-style packages and aliases without a bundler.

What import maps do

Import maps give the browser the information it needs to resolve bare module specifiers, the short package-style names such as preact or lodash that would otherwise only resolve inside a bundler. A native <script type="importmap"> maps those bare names to real URLs, so you can write normal import statements and the browser rewrites them to the resolved files. This removes the build step that traditionally turned bare specifiers into paths.

The feature is Baseline Widely Available, meaning every current engine resolves import maps natively: Chrome and Edge 89 and later, Firefox 108 and later, and Safari 16.4 and later. You do not need a polyfill for the basic single-map case. Because a single import map is parsed before any module that depends on it, declaring one inline in the head lets every later module import resolve to its target.

Declare a map

An import map is a JSON object mapping specifiers to URLs:

<script type="importmap">
{
  "imports": {
    "preact": "https://unpkg.com/preact/dist/preact.module.js",
    "logo": "/assets/img/logo.svg"
  }
}
</script>

<script type="module">
import { h } from "preact";
</script>

The import map must appear before the module that uses it. The mapping applies across the page, so any module can import preact and the browser fetches the mapped URL. You can map whole package prefixes as well as single files, which is how a set of subpath imports can share one root.

Scopes and support

scopes lets different contexts resolve the same bare name to different files. A prefix of the importing URL keys each scope, so one page can serve a debug build to development code and a production build to shipped code, or deliver a different version to a legacy area of the site. Libraries that ship an import map produce friendly bare-name setups; the map is the glue that connects them to the page.

Two support nuances are worth stating precisely. The single inline import map is fully Baseline; the newer addition of multiple import maps in one document is still a gap in Firefox, which keeps it behind a preference and off by default, so treat that as an enhancement rather than a requirement. Integrity metadata on import maps is now supported across engines (Firefox 138 and later, Chrome and Edge 127 and later, Safari 18.4 and later), so you can rely on it if you serve hashed map responses. After the page-level resolution, the modules themselves load like any other module, so the defer and async and module ordering rules still apply, and mapping a heavy package correctly does not by itself reduce the bytes the browser fetches, which is a separate bundle-shrinking concern.

Import maps fit the native modules approach that pairs well with web components, where shared component libraries import each other without a build step. If you are loading a package via an import map, verify the mapped URL serves a correct ES module, is on the same origin or a correct CORS header, and that the map stays in sync when the package version changes, because an outdated map points the browser at a stale file URL and produces exactly the resolution errors you removed the bundler to avoid.

Need a website built, fixed, optimised, migrated or replaced?

This technical resource is written by CSMBAC, a small design and development studio. If you would rather hand the problem to a professional, the website service page explains how we build enquiry-ready websites.

Explore website services