• NPM
    • Node.js
    • Tutorial
    • WebFiddle

    How to Use npm Packages in the Browser

    By Published Updated 5 min read

    Use npm packages in the browser without a bundler, using ES modules, import maps and ESM CDNs like esm.sh, plus what works in WebFiddle.

    To use an npm package in the browser without a build step, load an ES module version of it from a CDN such as esm.sh, and use an import map so you can write import confetti from 'canvas-confetti' instead of a full URL. For larger apps, a bundler is still the standard choice, while in-browser playgrounds load packages from CDNs as you add them.

    Key takeaways

    • Browsers can't resolve require('uuid') or bare specifiers like import React from 'react' on their own.
    • Native ES modules plus an import map tell the browser which URL each package name refers to. Import maps have been available across major browsers since March 2023.
    • ESM CDNs such as esm.sh serve npm packages as ES modules that you can import directly by URL.
    • Bundlers like Vite, webpack and Rollup remain the best option for production apps with many dependencies.
    • In WebFiddle, the React playground loads packages from CDNs, while the Node.js sandbox doesn't support external packages.

    The problem: require() doesn't exist in browsers

    For years, the Node.js and browser ecosystems were separate worlds. You could find a useful library on npm, such as uuid or lodash, but you couldn't use it directly in a <script> tag, because browsers have no require() function and no node_modules folder to look in.

    Bundlers such as webpack, Rollup and Parcel solved this. They run on your computer, follow every require() and import, and combine your code and its dependencies into files the browser can load.

    That works well for projects with a build step. But if you're writing code directly in a browser, such as in an online playground or a quick HTML file, running a full bundler on every keystroke is impractical.

    Native ES modules in the browser

    All modern browsers support JavaScript modules natively through <script type="module">:

    <script type="module">
      import { add } from './math.js';
      console.log(add(1, 2));
    </script>
    

    There's a catch: the browser needs a URL or a relative path (such as ./math.js or https://...). A bare module specifier like 'react' has no meaning on its own, so import React from 'react' fails unless something tells the browser where react lives.

    1. Import maps: the native solution

    An import map is a JSON object that controls how the browser resolves module specifiers. It maps bare names to real URLs. MDN lists import maps as widely available across browsers since March 2023.

    <script type="importmap">
    {
      "imports": {
        "canvas-confetti": "https://esm.sh/[email protected]"
      }
    }
    </script>
    
    <script type="module">
      // The browser resolves the bare name using the import map above
      import confetti from 'canvas-confetti';
    
      confetti();
    </script>
    

    Two rules to remember:

    • The import map must appear before any module script that relies on it.
    • Pin exact versions (@1.9.3) so a new release can't change your page unexpectedly.

    No build step or backend server is needed. You can try this snippet in the WebFiddle HTML preview.

    2. ESM CDNs

    Import maps only point to URLs, so something has to serve npm packages as ES modules. Many packages are still published in CommonJS format, which a <script type="module"> can't import.

    esm.sh describes itself as a way to "import JavaScript modules from http URLs, no installation/build steps needed". You request https://esm.sh/<package>@<version> and it returns an ES module you can import. It also documents how to use import maps with bare specifiers.

    Other CDNs, such as jsDelivr and unpkg, serve the files exactly as they're published to npm. That works when a package ships a browser-ready build, such as a UMD file that defines a global variable or an ES module file.

    3. How WebFiddle's playgrounds handle packages

    WebFiddle's sandboxes take different approaches, and none of them runs npm install in your browser:

    • React playground: when you add a package, the playground checks that it exists on the npm registry and records it in the project's package.json. The live preview loads React and ReactDOM as UMD builds, compiles your code in the browser with Babel, and adds a script tag for each dependency from jsDelivr, pointing to the package's dist/<name>.min.js file. That means packages with a browser build at that path work best. When you export a project as a standalone HTML file, the dependencies are written into an import map that points to esm.sh.
    • HTML preview: you can add your own <script> tags and import maps, as in the examples above.
    • Node.js sandbox: this runs in a Web Worker with a Node.js API shim, not real Node.js. require() throws a "module not found" error for every package and import statements aren't supported, so external packages can't be used there. How we run Node.js code in the browser explains why.

    When you need more than a CDN

    Some packages rely on Node.js-only APIs such as fs (the file system), net (raw sockets) or child_process. No CDN can make those work in a normal web page, because browsers don't provide those capabilities. Your options are:

    • Look for a browser-compatible alternative, or a package that documents browser support.
    • Run the code on a server or in a local Node.js install, and call it over HTTP.
    • Use a bundler that substitutes browser-friendly replacements for some Node.js modules, where the package allows it.

    Summary

    1. For quick pages and prototypes: use native ES modules with an import map pointing at an ESM CDN.
    2. For CommonJS-only packages: use a CDN such as esm.sh that serves them as ES modules.
    3. For production apps: use a bundler such as Vite for dependency locking, tree-shaking and caching.
    4. For Node.js-only packages: run them in real Node.js, not the browser.

    For more on modern JavaScript modules and syntax, see our guide to ES6 features.

    Frequently asked questions

    Can I use npm packages in the browser without a bundler?

    Yes, as long as the package works in browsers. Load an ES module version from a CDN such as esm.sh, either by importing its full URL or by mapping the package name to that URL with an import map. Packages that depend on Node.js-only APIs, such as fs or child_process, still won't work.

    What is an import map?

    An import map is a JSON block inside a script tag with type importmap. It tells the browser which URL to load when code imports a bare module name like react. It must be declared before any module scripts that use it. MDN reports that import maps have been widely available across browsers since March 2023.

    Why does import React from 'react' fail in the browser?

    Browsers resolve module imports as URLs or relative paths. The name 'react' is a bare specifier, which the browser can't find without help, since there's no node_modules folder on the web. Add an import map that maps react to a CDN URL, or use a bundler that rewrites the import during your build.

    Does the WebFiddle Node.js sandbox support npm packages?

    No. The Node.js sandbox runs in a Web Worker with a small Node.js API shim rather than real Node.js. Its require function throws a module-not-found error for every package, and import statements aren't supported. For packages, use a local Node.js install, or try browser-compatible libraries in the WebFiddle React playground or HTML preview.

    What is the difference between esm.sh and unpkg?

    unpkg and jsDelivr serve package files exactly as they were published to npm, which works when a package includes a browser-ready build. esm.sh serves packages as ES modules you can import directly from its URLs, including many packages that were originally published only in CommonJS format, and it documents how to use them with import maps.

    Try the examples yourself

    Open the Node.js sandbox to run and edit code from this article in your browser. There is nothing to install and no account to create.