ES Modules Logo ESModules.com

Import Maps

Import Maps let you use npm-style bare specifiers in the browser without a bundler. Map package names to URLs, pin versions, and scope dependencies natively.

Getting Started

An import map is a JSON object in a <script type="importmap"> tag that maps bare specifiers to URLs:

<script type="importmap">
{
  "imports": {
    "lodash": "https://esm.sh/[email protected]",
    "react": "https://esm.sh/react@19",
    "react-dom/client": "https://esm.sh/react-dom@19/client"
  }
}
</script>

<script type="module">
  // Now bare specifiers work - just like in Node.js!
  import { debounce } from 'lodash';
  import React from 'react';
  import { createRoot } from 'react-dom/client';

  const debouncedLog = debounce(console.log, 300);
</script>

No Bundler Required!

Import maps enable using npm packages directly in the browser. Combined with CDNs like esm.sh or jspm.io, you can build applications without any build step.

Path Mapping & Prefixes

Map entire package directories using trailing slashes, or create path aliases:

<script type="importmap">
{
  "imports": {
    "lodash/": "https://esm.sh/[email protected]/",
    "@/": "./src/",
    "#components/": "./src/components/",
    "#utils/": "./src/utils/"
  }
}
</script>

<script type="module">
  // Import specific lodash functions
  import debounce from 'lodash/debounce';
  import throttle from 'lodash/throttle';

  // Use path aliases (like TypeScript paths)
  import { Header } from '@/components/Header.js';
  import { formatDate } from '#utils/date.js';
</script>

Scoped Imports

Different parts of your app can resolve the same specifier to different URLs. This solves version conflicts:

<script type="importmap">
{
  "imports": {
    "lodash": "https://esm.sh/[email protected]"
  },
  "scopes": {
    "/legacy-widget/": {
      "lodash": "https://esm.sh/[email protected]"
    },
    "/admin-panel/": {
      "lodash": "https://esm.sh/[email protected]",
      "chart.js": "https://esm.sh/chart.js@4"
    }
  }
}
</script>

<!-- Modules in /legacy-widget/ get lodash v3 -->
<!-- Everything else gets lodash v4 -->

CDN Patterns

Use CDNs that serve npm packages as ES Modules:

<script type="importmap">
{
  "imports": {
    "react": "https://esm.sh/react@19",
    "three": "https://esm.sh/[email protected]",
    "zod": "https://esm.sh/[email protected]",
    "date-fns": "https://esm.sh/date-fns@4"
  }
}
</script>

esm.sh

Auto-converts npm packages to ESM. Supports TypeScript types. Recommended for most use cases.

jspm.io

JSPM Generator creates import maps automatically from package.json dependencies.

unpkg.com

Serves files directly from npm packages. Use ?module query for ESM output.

Dynamic Import Map Generation

Generate import maps dynamically for advanced use cases:

// Generate an import map from your dependencies
const importMap = {
  imports: {
    'lodash': `https://esm.sh/lodash-es@${LODASH_VERSION}`,
    'react': `https://esm.sh/react@${REACT_VERSION}`
  }
};

const script = document.createElement('script');
script.type = 'importmap';
script.textContent = JSON.stringify(importMap);
document.head.appendChild(script);

// IMPORTANT: Import map must be added BEFORE
// any module scripts are loaded

Rules:

  • Only one import map per document
  • Must appear before any type="module" scripts
  • Cannot be modified after module loading begins
  • Must be inline (no external src attribute)

Browser Support

Browser Version Release Date
Chrome 89+ March 2021
Edge 89+ March 2021
Firefox 108+ December 2022
Safari 16.4+ March 2023

Universal Support (2024+)

Import Maps are supported by 95%+ of global browser users. No polyfill needed for modern browser targets.

Frequently Asked Questions