# bwip-js: a barcode generator written in JavaScript that covers a hundred symbologies

> A translation of Barcode Writer in Pure PostScript to native JavaScript, rendering to PNG, SVG or canvas, with a warning about one upstream change that silently resized every symbol.

**metafloor/bwip-js** — Barcode Writer in Pure JavaScript

- Repository: https://github.com/metafloor/bwip-js
- Stars: 2,420 · Forks: 331
- Language: JavaScript
- License: NOASSERTION
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/metafloor-bwip-js

## A PostScript barcode writer compiled into JavaScript

The origin explains most of the design. bwip-js is a translation to native JavaScript of the code provided in Barcode Writer in Pure PostScript, and the README credits that project as the source rather than claiming an independent implementation. The consequence is that the symbology coverage is inherited: encoding modules for over a hundred different barcode types and standards, with all linear and two-dimensional barcodes in common use available alongside many uncommon ones.

The second consequence is that options are inherited too, and they come in two flavours. The bwip-js options control rendering. The BWIPP options control the symbol itself. The README separates them explicitly, which is useful because a barcode's quiet zone is a different problem from its module width.

The rendering options start small. Only two values are required: `bcid`, the name of the barcode type, and `text`, the content to encode. Everything else is optional. `scaleX` and `scaleY` are integer scaling factors above zero, `scale` sets both at once, and `scaleY` defaults to `scaleX`. `rotate` accepts one of four orthogonal orientations as a string: `'N'` for normal, `'R'` for clockwise 90 degrees, `'L'` for counter-clockwise 90 degrees and `'I'` for an inverted 180 degrees, with normal as the default.

Padding is where most of the remaining options live, and they are written as shorthands rather than independent values: `padding` sets top, left, right and bottom together, `paddingwidth` sets left and right, `paddingheight` sets top and bottom. There is also `binarytext`, which defaults to encoding the `text` string as UTF-8 binary bytes and can be disabled by setting the flag to `true` when the text is already 8-bit encoded.

## Five npm packages for five places your code might run

The packaging is the part of this project most likely to surprise you, because the main package is not the one you want in most cases. The README states the package has been partitioned into four platform-specific packages plus the main cross-platform package, and that if you install the main package and cannot get its exports to work with your build stack, the fix is to install a platform-specific one.

The main package installs like any other:

```bash
npm install bwip-js
```

And the four specific ones are:

```bash
npm install @bwip-js/node
npm install @bwip-js/browser
npm install @bwip-js/react-native
npm install @bwip-js/generic
```

What each one exposes is the point. The node, browser and react-native packages include both an image rendering interface, `toBuffer()` on node, `toCanvas()` on the browser and `toDataURL()` on react-native, plus the SVG and custom drawing context interfaces. The generic package contains only the exports that run anywhere, meaning SVG and the custom drawing context.

That generic package is the one to reach for if you are generating a barcode server side and want no assumptions about the environment. SVG output has no native dependency and no binary buffer, so it will not break on an unfamiliar runtime.

The package manifest backs this up with conditional exports for `browser`, `electron`, `react-native` and `node`, each pointing at its own type declarations, ES module build and CommonJS build. There are also subpath exports for `./browser`, `./node`, `./react-native` and `./generic`, so a bundler that understands the exports field will pick the right build without configuration.

One asymmetry is documented rather than hidden. The platform-specific packages are ES modules only, so you need a modern build environment. The exception is the node package, which also ships a `require()` compatible export.

## The guarddescent change that resized every EAN symbol

There is a warning near the top of the README about users of `ean2`, `ean5`, `ean8`, `ean13`, `upca`, `upce` and `isbn`, and it is worth reading in full because it is the kind of change that silently alters output rather than throwing an error.

A recent release of BWIPP added a `guarddescent` option, and that changed the final image height for those symbologies. Previously the symbol height was determined by the long guard bars. New releases determine height using the short bars instead. The result is that the image height increases by 5 pixels at `scale=1`, 10 pixels at `scale=2`, and so on. To get the old height back you either decrease `height` by 1.75mm or set `height` to 23.6mm if you were using the default.

So the practical effect is a layout shift, not a rendering failure. If you print barcodes onto preformatted labels with fixed pitch, a change of half a millimetre moves the whole symbol relative to the label, and nothing in your application will tell you. The README says the change appears in version 4.10, so anything below that keeps the old geometry.

A second note covers version 4.8, which added the text layout features from recent BWIPP releases. If you use a custom drawing interface and want the new text capabilities, the README points at the annotated example drawing object documentation and tells you to look for the `font.rotate` property passed into the `text()` method. That is a narrower audience, but it tells you the custom drawing context is treated as a first-class surface rather than a fallback.

Neither note is an apology and neither is treated as one. They read as the maintenance burden of tracking an upstream PostScript implementation, stated plainly so that anyone whose output changed can understand why.

## Output targets, a command line tool, and an online API

The rendering targets are listed as PNG images on node and react-native, to a canvas in the browser, and as SVG on all platforms. That list is the core technical argument for this library: if you need the same symbol on a server, in a browser and in a mobile app, one implementation that targets all three removes the reason to maintain three.

Beyond the library, the repository ships several other things. There is an online barcode generator demo that demonstrates all of the features, and the README notes the app is also available in the root bwip-js directory, which corresponds to `demo.html` at the top of the repository tree. There is an online barcode API service that serves barcode images on demand, and you can embed those URLs directly in HTML documents or retrieve the images from a server that does not run JavaScript. The README is blunt about which to use: JavaScript-based servers should call the library directly, because it will be a lot more performant.

That advice is the practical decision rule. The hosted API is for embedding in documents or for sites where running JavaScript is not an option. Once you control a server that runs Node, calling the library directly is faster and avoids a network hop per barcode.

The command line interface is a separate supported platform in the README's list, alongside browser, Node.js, SVG, React, React Native and Electron. The manifest declares a `bin` entry, which is what installs that executable.

The repository tree gives a sense of the size of the project: `src/` for the source, `lib/` for generated output, `dist/` for the npm builds, `bin/` for the command line entry point, `examples/` with ten files, `fonts/` for barcode fonts, and four separate licence files at the top level, `LICENSE`, `LICENSE.CANVASTOBLOB`, `LICENSE.FILESAVER` and `LICENSE.INCONSOLATA`, alongside a copy of the upstream `barcode.ps`. That is a mature repository rather than a small one, and the last three releases are typographical and bug fixes: v4.11.2 fixed an error in the command line tool, v4.11.3 fixed two issues, and v4.11.4 fixed a typo in an SVG fill rule.

## What to compare it against, and what the version pairing means

The alternatives split by category, and only one category is really comparable.

Server-side tools like Zint and Ghostscript render barcodes too, and they have an advantage that bwip-js cannot match: they are installed once on a machine you control and they run without a JavaScript runtime. For a batch job printing ten thousand labels from a Python pipeline, calling a binary is a reasonable choice. For anything inside a web application, adding a system package is an operational cost most teams would rather not take.

Client-side JavaScript libraries are the closer comparison. Most are narrower: they cover a handful of popular symbologies rather than a hundred, and they usually draw to a canvas only. If you need Code 128, EAN-13 and QR, a small focused library is less code to audit. If you need the less common retail and industrial symbologies as well, the coverage argument decides it.

The hosted barcode API mentioned earlier is the third option, and it removes the dependency entirely at the cost of a network request per barcode and a dependency on someone else's uptime.

The version pairing deserves attention. The README reports two separate numbers: current bwip-js version 4.11.4 from 2026-08-19, and current BWIPP version 2026-05-28. Each release tag carries both, as in v4.11.4 which reads bwip-js 4.11.4 (2026-08-19) / BWIPP 2026-05-28. So the JavaScript library and the PostScript original are versioned on different schemes and update on different schedules. If you are migrating from another PostScript-based pipeline, the BWIPP number is what tells you which upstream behaviour you are getting.

## Conclusion

bwip-js is the option when your barcode has to be drawn in the browser, on Node, in React Native and in Electron without four different dependencies, and the breadth of supported symbologies is genuinely hard to match elsewhere in JavaScript. Its rough edges are known and documented, including the `guarddescent` change that resized every EAN-family symbol in 4.10. Before you adopt it, check the version pairing: the library is at 4.11.4 while the PostScript original it tracks is at 2026-05-28, so the two are on separate clocks. The last push was on 2026-08-19, the same day v4.11.4 shipped.

## FAQ

### What are the two types of barcodes?

Linear barcodes encode data across parallel bars and need a scanner that sweeps the symbol, while two-dimensional symbols such as QR codes encode in both axes and are read with a camera or an area scanner. The README states that bwip-js covers both categories, with encoding modules for over a hundred types and standards.

### Which npm package should I install for bwip-js?

The main `bwip-js` package resolves per environment through conditional exports for browser, electron, react-native and node. If your bundler cannot resolve those, install a platform package instead: `@bwip-js/node`, `@bwip-js/browser`, `@bwip-js/react-native` or `@bwip-js/generic`, which is the one with only the SVG and custom drawing context exports.

### What output formats can bwip-js produce?

PNG images on node and react-native, a canvas in the browser, and SVG on all platforms. The image methods are `toBuffer()` on node, `toCanvas()` on the browser and `toDataURL()` on react-native, and the SVG and custom drawing context interfaces are available everywhere.

### Why did my EAN-13 barcode image get taller after upgrading bwip-js?

A recent release of the upstream BWIPP code added a `guarddescent` option that determines symbol height from the short bars rather than the long guard bars, which increases image height by 5 pixels at scale 1. The README says to decrease `height` by 1.75mm, or set it to 23.6mm, to restore the previous height, and that the change appears in version 4.10.

## Sources

- [Issues](https://github.com/metafloor/bwip-js/issues)
- [metafloor/bwip-js on GitHub](https://github.com/metafloor/bwip-js)
- [README](https://github.com/metafloor/bwip-js/blob/master/README.md)
- [Releases](https://github.com/metafloor/bwip-js/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/metafloor-bwip-js
