Barcode Types Explained: Code 128 vs EAN vs UPC

🏷️ Barcodes⏱️ 7 min readFree tool included

Every linear barcode is the same trick — dark bars and light spaces of varying widths — but each symbology is a dialect with its own alphabet, length rules, and check digit. Pick the wrong dialect and either the scanner won't read it or, worse, a retailer's system will reject it. Here's the field guide, with the check-digit math worked out on real numbers.

Advertisement

What all barcodes share

A linear barcode encodes data as a sequence of bars and spaces measured in modules (the narrowest bar). The symbology defines which widths are legal, what characters exist, how the string starts and stops, and usually a check digit that lets the scanner verify the read. Fixed-length retail codes (EAN, UPC, ITF-14) are dense and fast; variable-length codes (Code 128, Code 39) trade density for flexibility.

Two physical rules matter as much as the encoding. Print contrast: dark bars on a light background — red bars on white can be invisible to a red-laser scanner. And the quiet zone: blank space on each side, at least 10× the module width by the GS1 minimum (UPC-A gets 9×; EAN-13 gets 11× left, 7× right). Crop it and scan rates collapse.

Code 128: the workhorse

Code 128 encodes all 128 ASCII characters at variable length by switching between three code sets (A: uppercase and controls, B: upper and lower case, C: digit pairs packed two per symbol). An encoder picks the densest mix automatically. A mandatory mod-103 check character is computed and encoded but never printed. If your barcode carries a serial number, a URL fragment, a lot code, or anything with mixed case and punctuation, this is the default answer.

GS1-128 is Code 128 wearing a standard: the data is wrapped in Application Identifiers like (01) for a GTIN and (17) for an expiry date, so a single symbol on a shipping label can say "product X, expires 2026-01-01, lot 42" in a format any logistics scanner understands.

Code 39: the legacy survivor

Forty-three characters — digits, uppercase letters, space, and - . $ / + % — each built from 9 elements with 3 wide. It's less dense than Code 128 (every character is wider), but it's been around since 1974 and prints forgivingly on bad printers, which is why defense, automotive, and older warehouse systems still speak it. The mod-43 check character is optional and often omitted.

EAN-13 and UPC-A: the retail gatekeepers

These are the point-of-sale codes. EAN-13 carries 12 digits plus a check digit; UPC-A carries 11 plus a check. They're structurally near-identical (95 modules wide), and most scanners treat them as one family. The real difference is registration: the leading digits of an EAN/UPC encode a GS1 company prefix, and that prefix is what you're actually buying when you license numbers from GS1.

You can draw any EAN-13 you invent, and it will scan. But put an invented code on a product headed for a store and the chain's catalog will refuse it, because the prefix belongs to someone else (or nobody). Invented numbers are fine for internal shelf labels, prototypes, and price-check kiosks you control.

The check digit, on real numbers

The mod-10 algorithm, once, slowly. Payload: 400638133393 (12 digits). Weight them 1,3,1,3… from the left and multiply:

4×1 + 0×3 + 0×1 + 6×3 + 3×1 + 8×3 + 1×1 + 3×3 + 3×1 + 3×3 + 9×1 + 3×3 = 89

The check digit is the distance to the next ten: 90 − 89 = 1, so the printed barcode is 4006381333931. UPC-A runs the same math on 11 digits (03600029145 weights to 58, so the check digit is 60 − 58 = 2 → 036000291452), and EAN-8 on 7 digits (9638507 weights to 86, check 4 → 96385074). Our barcode generator computes and appends these automatically.

UPC-E and EAN-8: small packages

UPC-E is zero suppression: when a UPC-A's digits are mostly zeros in the right pattern, the code compresses to 6 data digits plus the number system (always 0) and the check digit. The expansion is deterministic — UPC-E 01234565 un-suppresses to the UPC-A body 01234500006, whose check digit is 5, so the full UPC-A is 012345000065. EAN-8 is the separate, genuinely short retail code (7 + 1 digits) for packages too small even for UPC-E — think a stick of gum.

ITF-14, Codabar, and MSI

ITF-14 encodes 13 digits plus a check on cartons and pallets — it's the outer-case level of the GS1 hierarchy, printed large and coarse because forklift scanners read it from meters away. Codabar (digits plus a few symbols, with A/B/C/D start-stop characters) lives on in library circulation and old blood-bank forms. MSI is digits-only and mostly found on warehouse shelves. All three are trivial to generate but increasingly niche; if you're starting fresh, use Code 128 or a 2D code instead.

SymbologyCharactersLengthCheck digitWhere you'll meet it
Code 128Full ASCIIVariableAuto mod 103IDs, logistics, healthcare
EAN-13Digits12+1Mod 10Retail POS worldwide
UPC-ADigits11+1Mod 10Retail POS, US/Canada
UPC-EDigits6+NS+1Mod 10 (expanded)Small US packages
EAN-8Digits7+1Mod 10Very small packages
ITF-14Digits13+1Mod 10Cartons, pallets
Code 3943 charsVariableOptional mod 43Defense, automotive legacy
CodabarDigits + symbolsVariableNoneLibraries, blood banks
MSIDigitsVariableOptional mod 10Warehouse shelves

Linear vs 2D: when to skip bars entirely

A linear barcode is a serial number; a QR or Data Matrix code is a database row. If you need more than ~50 characters, URL links, or damage tolerance, 2D wins outright — a QR code holds up to ~7,000 digits with error correction that survives a torn corner. The practical split: EAN/UPC for checkout scanners, Code 128 or 2D for everything you control. Our QR code generator and vCard QR tool cover the 2D side, and the asset tag generator prints Code 39 label sheets for equipment inventories.

Generate any of these right now

Code 128, EAN-13/8, UPC-A/E, Code 39, ITF-14 — live vector output with computed check digits, straight from your browser.

Open the Barcode Generator →

The bottom line

Match the symbology to the scanner, not the other way around: GS1-registered EAN-13/UPC-A for store checkout, Code 128 for your own IDs and logistics, ITF-14 on cartons, and quiet zones you refuse to crop. The check digit is ten seconds of arithmetic — weight 1-3, sum, subtract from the next ten — and it's the difference between a code that scans and a label that just looks like one.

Advertisement

Frequently Asked Questions

Which barcode do retailers require?

EAN-13 in most of the world, UPC-A in the United States and Canada. Both are fixed-length digit codes scanned at point of sale, and the numbers must come from GS1, the global standards body — retailers reject codes whose company prefix isn't registered. Internal labels, shipping cartons, and asset tags don't need GS1 numbers, which is where Code 128 and ITF-14 shine.

How do I calculate an EAN-13 check digit?

Weight the 12 payload digits 1,3,1,3 from the left, sum them, and subtract from the next multiple of 10. Payload 400638133393: 4x1 + 0x3 + 0x1 + 6x3 + 3x1 + 8x3 + 1x1 + 3x3 + 3x1 + 3x3 + 9x1 + 3x3 = 89, and 90 - 89 = 1, so the barcode is 4006381333931. UPC-A (11-digit payload) and EAN-8 (7-digit payload) use the same algorithm.

Can Code 128 encode letters and symbols?

Yes — all 128 ASCII characters, at any practical length. That's why it dominates for serial numbers, license-plate IDs, GS1 logistics labels (as GS1-128), and healthcare applications. Its check character (mod 103) is computed and encoded automatically but never printed as a human-readable digit.

Is UPC-E just a short UPC-A?

Yes, a compressed form of one specific UPC-A whose zeros can be squeezed out. UPC-E carries 6 digits plus number system 0 and the check digit; it always expands back deterministically. Example: UPC-E 01234565 expands to UPC-A 01234500006, whose mod-10 check digit is 5 — full code 012345000065.

What happens if I crop the quiet zone?

Scanners misread or refuse the barcode. The quiet zone is the blank margin around the bars, and the GS1 minimum is 10 times the narrow bar width on each side (UPC-A: 9x; EAN-13: 11x left, 7x right). When designers tighten label art to the bar edges, scan rates drop — leave the margin.