Blog

An Introduction to Browserify

Key Takeaways

  • Browserify follows CommonJS require() dependencies from an entry file and produces a browser-loadable JavaScript bundle.
  • Bundling does not turn the browser into Node.js or automatically transpile your source code.
  • Transforms, watch mode, source maps, and production minification require explicit configuration or additional tools.
  • Retain Browserify when an existing CommonJS pipeline meets your needs; evaluate native ES modules or a current application toolchain for new work.

Browserify is a JavaScript module bundler that packages CommonJS modules and their dependencies for use in a browser. In 2026, its strongest case is maintaining an existing application or supporting a deliberately small CommonJS build—not serving as the default build tool for a new application.

What Is Browserify?

Browserify lets you organize browser code using Node-style require() and module.exports. Instead of loading each source file with a separate script tag, you build an output file such as bundle.js and load that file in your page.

This is useful when you already have CommonJS application code or compatible npm dependencies. It is not a general-purpose converter for arbitrary server-side Node.js applications.

How Browserify Works

You give Browserify an entry file. It discovers that file's dependencies, follows their dependencies recursively, and packages the resulting module graph—the files and the connections between them.

The output is more than concatenated source files. Browserify's bundle packaging machinery wraps modules and includes a module loader that connects their require() calls to bundled exports.

Entry: src/index.js
        |
        v
Read each module
        |
        v
Apply configured transforms, if any
        |
        v
Discover and resolve require() dependencies
        |                         |
        +---- repeat for dependencies
        |
        v
Pack modules + module loader
        |
        v
dist/bundle.js --> HTML script tag --> browser

You no longer manage a script tag for every module. You still need to account for initialization side effects, circular dependencies, and any scripts that remain outside the bundle.

Browserify Tutorial: Install, Build, and Load a Bundle

1. Create a Small CommonJS Project

With Node.js and npm installed, run these commands in a terminal:

mkdir browserify-demo
cd browserify-demo
npm init --yes
npm install --save-dev browserify
mkdir src dist

Browserify is a build-time dependency, so this example installs it in devDependencies. The following commands use npx to run the locally installed executable.

2. Add an Entry File and a Reusable Module

Create src/greet.js:

module.exports = function greet(name) {
  return `Hello, ${name}!`;
};

Create src/index.js:

const greet = require('./greet.js');
const output = document.getElementById('message');

if (!output) {
  throw new Error('Missing #message element');
}

output.textContent = greet('Browserify');

These files intentionally use CommonJS because that is the module system this tutorial demonstrates. Modern JavaScript syntax and the module format are separate concerns.

3. Build the Bundle

npx browserify src/index.js -o dist/bundle.js

The Browserify CLI treats src/index.js as the entry point; -o writes the output to the specified file. Browserify includes the required greeting module without needing a separate entry for it.

4. Load the Generated File

Create index.html in the project root:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Browserify demo</title>
    <script src="./dist/bundle.js" defer></script>
  </head>
  <body>
    <p id="message"></p>
  </body>
</html>

Open the page in a current browser. It displays Hello, Browserify!. The defer attribute makes the external classic script execute after the document has been parsed, so the paragraph exists when the entry module runs.

Using npm Packages Without Assuming Node.js Compatibility

For an installed browser-compatible npm package, require it by package name rather than a relative file path. Browserify resolves package dependencies too, and its package resolution honors the browser field for browser-specific replacements.

That compatibility has limits. Browserify supplies selected browser shims—replacement implementations—for functionality such as events, path, and Buffer. A shim is not a complete Node.js runtime.

The Browserify handbook documents a particularly misleading case: require('fs') can resolve to an empty stub, but calling its missing filesystem methods still fails. Check the package's browser support and test the browser execution paths you actually use.

Transforms: Bundling Is Not Transpiling

Bundling combines modules. Transpiling rewrites source syntax for another target. Browserify transforms run configured build-time processing; they do not make compilation disappear.

Babelify connects Babel to Browserify. Install the transform, compiler, and preset separately:

npm install --save-dev babelify@10 @babel/core@7 @babel/preset-env@7

These major versions are intentional: Babelify 10 declares a Babel core peer dependency of ^7.0.0. Do not substitute a different Babel major without checking compatibility.

Create a babel.config.json configuration file in the project root:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": "defaults",
        "modules": "commonjs"
      }
    ]
  ]
}

Then rebuild with the transform enabled:

npx browserify src/index.js -t babelify -o dist/bundle.js

Here, -t babelify enables the transform. The preset-env configuration selects syntax transformations for the target browsers and converts ES module syntax to CommonJS when present. Replace the example target with your application's actual browser policy; this configuration does not automatically add runtime polyfills.

JSX requires separate configuration, such as an installed @babel/preset-react added to the presets list. Browserify and Babelify do not enable JSX support automatically. For a syntax refresher, see our JavaScript ES6 introduction.

Development and Production Build Trade-Offs

Source Maps and Watch Mode

Browserify's --debug flag adds an inline source map, which lets browser developer tools map bundled code back to source files. For incremental rebuilds after edits, install Watchify:

npm install --save-dev watchify
npx watchify src/index.js --debug -o dist/bundle.js

Watchify rebuilds the output as source files change; it is not an application development server. If your project needs Babelify, add -t babelify to this command too.

Production Minification

Minification is a separate step. For the plain CommonJS example, install Terser, build, and then compress and shorten local variable names:

npm install --save-dev terser
npx browserify src/index.js -o dist/bundle.js && \
  npx terser dist/bundle.js --compress --mangle --output dist/bundle.min.js

Update the HTML script path to ./dist/bundle.min.js. If your source requires Babelify, retain -t babelify in the production bundling command. Decide explicitly whether production source maps should be public, private, or omitted.

Bundle Size and Dependency Cost

A single output file is a deployment convenience, not a performance guarantee. Inspect included dependencies and shims, measure the delivered bundle, and test startup on representative devices.

Browserify supports multiple bundles through explicit configuration, but do not assume automatic application-level code splitting or unused-export removal. Our JavaScript performance tips cover the broader optimization work that bundling alone cannot replace.

Browserify vs Vite, Webpack, and Native ES Modules

Native browser ES modules use import and export, loaded through <script type="module">. They can eliminate a bundling step when your source and dependencies are already browser-ready. Bare package names need a resolution mechanism such as an import map; browsers do not search your local node_modules directory.

ApproachWhere It FitsMain Trade-Off
BrowserifyExisting CommonJS applications and narrowly scoped browser bundlesYou assemble transforms, watching, minification, and asset handling as needed.
Native ES modulesSmall browser-ready applications without compilation requirementsYou manage module URLs, dependency compatibility, and deployment yourself.
ViteNew applications needing an integrated development server and production buildMigration requires adapting entry points, configuration, and incompatible dependencies.
WebpackApplications needing configurable module and asset processingIts loader and plugin configuration can require more build-system ownership.

Bundling still earns its place when you need dependency conversion, source transforms, or a particular deployment artifact. But calling Vite or Webpack “overkill” is not enough to justify Browserify: compare the complete pipeline you would maintain. See our guide to JavaScript build tools for the broader decision.

A framework toolchain that already handles your application build generally does not need Browserify layered on top. Keep a separate Browserify build only when it produces a distinct artifact with a clear owner.

Should You Keep Browserify or Migrate?

When checked on October 17, 2026, Browserify's GitHub releases page listed v17.0.1 as the latest release. That establishes the tagged-release state; it does not establish a support commitment or prove that your entire plugin chain is maintained.

  • Keep it when builds are reproducible, dependencies remain acceptable, browser tests pass, and the pipeline meets your delivery needs.
  • Plan migration when incompatible packages, unsupported plugins, browser failures, or build-system workarounds are becoming recurring costs.
  • For new work, start by evaluating native ES modules or a current application toolchain. Choose Browserify only when its CommonJS model and operational constraints are deliberate requirements.

Before migrating, inventory entry points, transforms, browser replacements, and output expectations. Prove one representative entry in the replacement toolchain, compare behavior and bundle size, and keep a rollback path.

Common Mistakes

  • Loading source instead of output: Point the HTML script tag at the generated bundle, not the CommonJS entry file.
  • Changing only the module syntax: Replacing require() with import does not resolve Node-only APIs or deployment assumptions.
  • Masking incompatible dependencies: Empty stubs can allow bundling while leaving broken runtime paths.
  • Trusting an old successful build: Recheck browser behavior, dependency risk, and transform compatibility after changes.

Production Checklist

  • Commit the lockfile and use npm ci for clean, lockfile-based installs in continuous integration.
  • Install build-time dependencies in the build environment, even when you deploy only generated assets.
  • Test the minified artifact in supported browsers, not just the unminified development bundle.
  • Review direct dependencies, transitive dependencies, and build plugins for security and maintenance risk.
  • Never put secrets into browser-bound source or build-time replacements.

Conclusion

Browserify remains understandable and useful within its CommonJS niche. Keeping a working pipeline can be the sensible engineering decision; choosing it for a new application needs a stronger justification than “fewer configuration files.” Judge the complete build, its dependency risk, and its migration cost.

FAQ

What does Browserify do?

Browserify follows CommonJS require() dependencies from an entry file and packages the required modules with a module loader into browser-loadable JavaScript. It does not provide a complete Node.js runtime.

How do I create a Browserify bundle?

Install Browserify with npm install --save-dev browserify, create the output directory, and run npx browserify src/index.js -o dist/bundle.js. Load dist/bundle.js from an HTML script tag.

Can Browserify bundle every Node.js module for the browser?

No. Browserify can bundle compatible CommonJS dependencies and provide selected browser shims, but packages that require Node-only runtime capabilities need replacements or architectural changes. A successful bundle is not proof of browser compatibility.

Is Browserify still maintained?

On October 17, 2026, Browserify's GitHub releases page listed v17.0.1 as the latest release. Release availability alone does not establish ongoing support; check repository activity, unresolved compatibility issues, and the maintenance of your transforms and dependencies.

Should I use Browserify or Vite for a new project?

For a new application that needs a development server and production build, evaluate Vite before assembling a Browserify pipeline. Before choosing, check whether native ES modules meet your deployment needs and whether you actually need a CommonJS bundling pipeline.

Further Reading

Written by Sam Erickson

Software engineer. I write every article on StackChief myself. Author of Mastering the Tech Interview. More about me