npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

payload-barcodes

v1.0.0

Published

Barcodes and QR codes for Payload products: pick the field, get a printable code on every item, with no runtime dependencies.

Readme

payload-barcodes

npm node license payload ecommerce

Gives every Payload product a barcode and a QR code, drawn from a field you choose, on a printable page that is black on white and nothing else. The encoders are part of this package: no runtime dependencies, no image service, no external call.

  • Code 128, EAN-13 and QR written from the specification, not wrapped from a library
  • The shop chooses which field holds the code, in the admin panel
  • Filled in automatically on every save, and searchable
  • One page for a single label or for a whole selection, ready for the printer
  • The main entry imports no React at all

Compatibility

| Requirement | Version | Declared as | | --- | --- | --- | | payload | >=3.88 <4 | peer dependency | | @payloadcms/plugin-ecommerce | >=3.88 <4 | peer dependency | | react | >=19 <20 | optional peer dependency, only for the print buttons | | Node | >=20 | engines |

The floor is the version this package was actually tested against. Verified end to end on Payload 3.88.0 with the official ecommerce plugin on PostgreSQL.

Install

Requires Payload 3.88 or newer and @payloadcms/plugin-ecommerce 3.88 or newer.

pnpm add payload-barcodes
import { barcodesPlugin } from 'payload-barcodes'

export default buildConfig({
  plugins: [
    barcodesPlugin({
      collections: ['products'],
    }),
  ],
})

Then open Barcodes in the admin panel and name the field that holds the code, for example sku. Nothing is generated until you do.

What was measured

Measured on 21 August 2026 against @payloadcms/plugin-ecommerce 3.88.0 and the npm registry.

| Question | Answer | | --- | --- | | Does the ecommerce plugin produce a barcode or a QR code? | No. Neither term appears in it | | Is there a barcode or QR plugin for Payload? | None on the registry | | Do products carry a code field? | No |

The encoders are verified, not assumed

Every QR code this package draws is read back by an independent decoder in the test suite. The sweep covers versions 1 to 10 at all four error correction levels:

723 codes encoded, 723 decoded correctly, 0 failures

That check runs in CI on every push, so a regression in the encoder cannot pass unnoticed.

The barcodes are checked against published article numbers. 590123412345 gives check digit 7, 400638133393 gives 1, 978020137962 gives 4, 501234567890 gives 0. An EAN-13 pattern is 95 modules wide with guards at 101, 01010 and 101; a Code 128 pattern is eleven modules per symbol plus a thirteen module stop.

Verified in a live install

| Test | Result | | --- | --- | | Admin names slug as the source field | Code filled in on save, indexed and searchable | | A source value the CMS transforms | Recorded value matches the stored value, not the submitted one | | QR set to a URL template | Page scanned back as https://shop.example/p/walnut-table-99 | | Print page | HTML, #000 and #fff only, prints on load | | Several ids at once | One page, one label per product, no label split across pages | | Value that is not a valid EAN-13 | Recorded with a plain explanation instead of a broken drawing | | Print endpoint without a token | 403 |

How it works

The plugin adds three things: a code group on each named collection, a settings global, and one endpoint.

Recording. An afterChange hook reads the source field and stores the value, the symbology, and an explanation when the value cannot be drawn. It runs after the write on purpose: a field hook may still transform the value, a slug being the usual case, and a code that does not match the field it came from is worse than none.

The hook writes only when something changed, and marks the request so its own save cannot re-enter it.

Drawing. The images are never stored. Both codes are drawn when the page is requested, so changing a setting changes every label immediately and nothing in your database goes stale.

Printing. The endpoint returns one complete HTML page holding every label, with page-break-inside: avoid so a label is never split. It opens the print dialog on load. There are no colours, no images and no scripts beyond that one call.

Options

| Option | Default | Meaning | | --- | --- | --- | | collections | required | Collections that get a code, by slug | | disabled | false | Stops recording, leaves fields and settings in place | | fieldName | 'barcode' | Name of the field group holding the code | | settingsSlug | 'barcodes' | Slug of the settings global |

Settings

| Setting | Meaning | | --- | --- | | Source field | Field read for the code, for example sku. Nothing happens until this is set | | Format | Code 128 for any printable ASCII, or EAN-13 for thirteen digit article numbers | | QR code carries | The same value, or a URL built from it | | URL template | Where {value} is replaced by the code, URL encoded | | Print the value under the code | Adds the value in monospace under the bars |

What it adds to your database

| Where | Field | Notes | | --- | --- | --- | | each named collection | barcode group | value (indexed), format, and error when the value cannot be drawn | | new global barcodes | source field, format, QR source, URL template, caption | Appears in the admin menu under Ecommerce |

The settings are an ordinary Payload global, which is why they reach the menu without this package shipping an admin component.

Printing

GET /api/barcodes/print?collection=products&id=42&type=barcode
GET /api/barcodes/print?collection=products&id=1,2,3&type=qr

Requires an authenticated user and reads each document with the caller's own access rights. type is barcode or qr. Several ids give one page with one label each.

The two buttons

The endpoint is enough on its own. If you want the buttons inside a document, import them from the separate client entry:

import { PrintButtons } from 'payload-barcodes/client'

<PrintButtons collection="products" id={id} />

They render exactly Print Barcode and Print QR Code, with no styling of their own beyond spacing, so they inherit your admin theme.

This is a deliberate split. The main entry contains no React, which is what keeps the package on the part of Payload's surface that survives minor releases. The buttons are opt in, and if they ever break, the printing itself does not.

Honest limits

QR codes go up to version 10. That is 271 bytes at level L, 213 at M. It covers an article number, a SKU or a product URL comfortably. A longer value is refused with a clear message rather than silently truncated.

Code 128 uses set B only. Printable ASCII from space to tilde. Set A control characters and set C numeric compression are not implemented, so a long numeric code is wider than it strictly needs to be. Anything outside set B, Greek included, is refused with an explanation.

EAN-13 is validated, not corrected. A value that is not thirteen digits with a matching check digit is recorded with an error and no barcode is drawn. completeEan13 is exported if you want to add the check digit yourself. The QR code is still drawn in that case.

Recording costs a second write on the first save. The hook runs after the document is written, so a new document is saved twice: once by you, once to record the code. Later saves write only when the value actually changed.

The print page carries no fonts of its own. It uses the system stack, so a label printed on one machine may be a hair wider than on another. The codes themselves are vector and exact.

Codes are not checked for uniqueness. Two products may carry the same value if the source field allows it. Put a unique index on your source field if that matters.

License

MIT. Copyright George Vasiliades, https://github.com/Poseidonas