Code 128 vs Code 39: Why Modern Retail Moved On

A technical comparison of Code 128 and Code 39 barcodes, covering character sets, density, check digits, and when each is the right choice. Code 39 survives on legacy mandates, and Code 128 wins everywhere else.

Code 39 and Code 128 are both linear alphanumeric barcodes, and on a label they look nearly identical. On character set, density, check digit reliability and standards compliance, Code 128 is the better format. Code 39 is still printed on millions of labels every day in warehouses, government facilities and automotive plants. This guide explains what each format is, how they compare, and the one circumstance where Code 39 is still the right answer.

Code 39, the original alphanumeric barcode

Code 39 was invented in 1974 by Intermec (David Allais and Ray Stevens). It is one of the oldest barcodes still in production use. The name "3 of 9" describes its structure. Each character is 9 elements (5 bars and 4 spaces), and exactly 3 of them are wide. The pattern of which 3 are wide identifies the character. Using only two widths was a deliberate choice for the printing of the era. Two widths tolerate ink spread and press variation better than several precise widths.

Code 39 encodes exactly 43 characters.

  • 26 uppercase letters (A-Z)
  • 10 digits (0-9)
  • 1 space
  • 6 symbols, the hyphen -, period ., dollar sign $, forward slash /, plus sign + and percent sign %

There are no lowercase letters and no exclamation marks, colons, at-signs or brackets. The asterisk (*) is the start and stop delimiter and cannot be encoded as data. If you need lowercase or extended ASCII, you are already in Code 128 territory.

Code 39's check digit is optional. The base standard does not require it. When it is used, it is a Mod 43 sum. Assign each character a value from 0 to 42, add them up, and the remainder mod 43 is the check character. Because it is optional, the encoder and the scanner can disagree about it. Print a Code 39 with the check digit on and read it with a scanner that has verification off. The scanner returns the check character as an extra letter at the end of the data string, and your application rejects the read. Match the encoder and scanner configuration and the problem goes away.

Code 128, the modern standard

Code 128 was invented in 1981 by Computer Identics and is standardised as ISO/IEC 15417. The name refers to the 128 ASCII characters it encodes. It is the base of GS1-128, the GS1 standard used on USPS IMpb shipping labels, retail case labels and pharma logistics labels.

Code 128 has three subsets, and a single symbol can switch between them mid-stream. The summary is below. For the full encoding rules see the Code 128 subsets reference.

  • Code A covers ASCII 0-95, including control characters (null, tab, linefeed) and uppercase letters. Use it when the payload needs control characters.
  • Code B covers ASCII 32-127, every printable character including lowercase. It is the default for alphanumeric content.
  • Code C encodes numeric pairs, two decimal digits (00-99) per codeword. For all-digit payloads the symbol is roughly half the length of Code A or B. A 20-digit serial number in Code C is far shorter than the same number in Code 39.

A good encoder picks the best subset automatically and switches mid-symbol when that saves space. The encoder in bwip-js, which powers Barcode Press, does this.

Code 128's check character is mandatory and automatic. It is a mod-103 weighted sum of all codewords, embedded in the symbol, and the scanner verifies it on every read. There is no configuration decision to make. It is always there, always checked, and invisible to the user.

Side-by-side comparison

FeatureCode 39Code 128
Year invented19741981
Character set43 chars (uppercase, digits, 6 symbols)128 chars (full ASCII, all printable + control)
Lowercase lettersNo (requires extended variant)Yes (Code B natively)
Check digitOptional (Mod 43)Mandatory, automatic (Mod 103)
Density vs Code 12824-143% wider for same dataBaseline
ISO standardISO/IEC 16388ISO/IEC 15417
GS1 complianceNot applicableGS1-128 standard
Numeric-only modeNoYes (Code C, 2 digits/codeword)

How much smaller Code 128 is, measured

The table shows symbol widths in modules (at scale 1) for the same payload in both symbologies, measured from bwip-js output.

PayloadCode 39 widthCode 128 widthCode 39 wider by
HELLO (5 uppercase chars)112 modules90 modules+24%
PART-12345-A (12 chars)224 modules167 modules+34%
1234567890 (10 digits)192 modules90 modules (Code C)+113%
12345678901234567890 (20 digits)352 modules145 modules (Code C)+143%
hello (5 lowercase, ext vs Code B)192 modules (extended)90 modules+113%

For mixed uppercase alphanumeric content, Code 128 is 24-34% shorter. For numeric-only data, Code 128 in Code C is more than twice as compact as Code 39. For lowercase or mixed-case data, Code 128 wins by a factor of 2 or more. On a small label, that gap is what lets the symbol fit at all.

Code 39 Extended is a dead end

Code 39 Extended (also called Full ASCII Code 39) encodes all 128 ASCII characters with shift pairs from the base 43-character set. Each extended character takes two Code 39 codewords, which roughly doubles the data portion of the symbol for mixed-case content.

Use Code 128 for lowercase and full ASCII. Code 39 Extended is wider than Code 128 for the same data and needs the scanner's Full ASCII mode switched on. Code 128 encodes the same characters in half the width with no scanner configuration.

Why supply chains standardised on Code 128

GS1-128 is the Application Identifier standard built on Code 128. Two- to four-digit AI codes in parentheses prefix each field. (01) is the GTIN, (17) the expiry date, (10) the lot number, (00) the SSCC (Serial Shipping Container Code), and there are dozens more. A single GS1-128 barcode carries a product identifier, expiry, lot and serial number in one symbol that scanners anywhere in the world read the same way.

USPS IMpb shipping labels are GS1-128, while UPS and FedEx print Code 128 tracking barcodes with MaxiCode or PDF417 alongside. Pharma case and pallet labels use GS1-128, and unit-level serialisation under DSCSA and the EU FMD uses GS1 DataMatrix. For retail supply chain case labels worldwide, GS1-128 is the standard. It runs on Code 128 only. There is no GS1-39. If any part of your supply chain involves GS1 compliance, Code 128 is a prerequisite.

Why Code 39 is still everywhere

Code 128 has been the better symbology since 1981. Code 39 persists for reasons unrelated to technical merit.

The first is legacy inertia. The installed base of scanners, ERP configurations, label templates and trading partner agreements built up over fifty years is enormous. Changing a label format means revalidating every reader in every warehouse and every downstream data system. For a stable product line with thousands of labels already in circulation, the migration cost is high and the benefit is modest, so "good enough" wins.

The second is industry mandates that predate Code 128. The US Department of Defense standardised on Code 39 for LOGMARS (Logistics Applications of Automated Marking and Reading Symbols, MIL-STD-1189B) before Code 128 existed. MIL-STD-1189B has since been cancelled, and MIL-STD-129 now carries the Code 39 requirement. The Automotive Industry Action Group (AIAG) published labelling standards that specify Code 39, and some suppliers are still contractually bound to them. These standards update slowly.

The third is implementation simplicity. Code 39 can be implemented with a lookup table and no check digit calculation, which made a difference on the label printers of the 1970s and 1980s with their minimal computing power. It is irrelevant to any modern system, and the legacy implementations it produced are still running.

The decision

SituationUse
New implementation, no legacy constraintsCode 128
GS1 or supply chain compliance requiredCode 128 / GS1-128 (mandatory)
All-digit serial numbers or GTINsCode 128 (Code C mode)
Lowercase or mixed-case dataCode 128
Trading partner specifies Code 39 by nameCode 39
DoD LOGMARS / specific AIAG mandateCode 39
Asset tags, label size not constrained, uppercase onlyEither (Code 39 acceptable)
Need lowercase, considering Code 39 ExtendedCode 128

Use Code 128 unless something external forces Code 39 on you. The density, the character set and the mandatory check digit all come free. Starting fresh with no mandate, Code 128 is the only sensible choice.

Try it

More guides