Build1 publisher2 min readPublished
Reading Shopify's barcode field will return one value after it grows to hold 20
Shopify's variant barcode field is set to hold 20 values while a read still returns one, according to a dev.to post on printing GS1 packaging labels. Teams that print case and carton labels from Shopify data depend on which value comes back.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

What happened
- GS1 gives each packaging level its own GTIN, with an EAN-13 on the consumer unit scanned at the till and ITF-14 GTIN-14s on cases and cartons.
- On Shopify's current stable API version, a product variant carries a single barcode string.
- The post's author needed four sticker layouts, for product, inner and carton labels plus a format some retailers insist on, carrying three identifiers between them.
- The author keeps inner and carton data outside Shopify, in a supplier portal that already held the packing specification.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- exposure A carton label that reuses the item GTIN would make a case of 24 book as one unit at goods-in, and the receiving warehouse is where that surfaces.
- decision Teams moving past one barcode per variant have to choose a home for pack quantities as well as GTINs, because every label count divides by them.
- cost Holding the packing hierarchy outside Shopify puts product data in two systems, and someone has to state which system owns each field.
labelsFor takes the packing hierarchy and an order line counted in consumer units, and returns two lists: labels and refusals [8]. Each level carries a GTIN, null when the supplier has not supplied one, plus a unitsPerPack count [8]. Label quantity per level is Math.ceil(orderedUnits / unitsPerPack) [8]. Item labels get EAN-13. Every level above gets ITF-14 [8]. On a 240-unit line, pack sizes of ten and 120 give the 24 inner and 2 carton labels [1]. The division rounds up, so 250 units would produce 25 inner labels and 3 carton labels [2]. A bad order count is rejected up front, and a level with a bad pack size is refused on its own [8].
I would copy the refusal branch. When a level's GTIN is null or blank, the function records a reason and moves to the next level, with no fallback to the item's number [9]. A fallback is tempting because it produces a label instead of an error. "A missing label stops the line. A wrong one is discovered in somebody else's warehouse," the author wrote [11]. In my view, refusing is the right default whenever cartons ship to a third party's dock. Refusals come back as data next to the labels, so the caller can show an operator which level is missing its number [8].
The author weighed metafields for the inner and carton numbers. They work, but they hold values, and nothing in a metafield knows that a carton contains ten inners [12]. The label counts depend on that relationship [12]. If Shopify's expanded field turns out to be a list of barcode strings, it has the same gap. A string can hold a GTIN-14 [2], but labelsFor also needs the pack size it divides by [8].
According to the post, the variant barcode field is about to hold 20 values while a read still returns one [5]. The author calls the migration detail more interesting than the feature [14]. The evidence available does not establish which value a single read returns, which API version brings the change, or when it ships. Integrations that read today's single string [4] and print it as the consumer unit's EAN-13 [2] depend on that answer.
What to watch
- Shopify's API changelog naming the version that adds multi-value barcodes, and which value the single-value read returns.
- Whether each value in the expanded field records a packaging level or pack quantity, or is a bare barcode string.