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
| Feature | Code 39 | Code 128 |
|---|---|---|
| Year invented | 1974 | 1981 |
| Character set | 43 chars (uppercase, digits, 6 symbols) | 128 chars (full ASCII, all printable + control) |
| Lowercase letters | No (requires extended variant) | Yes (Code B natively) |
| Check digit | Optional (Mod 43) | Mandatory, automatic (Mod 103) |
| Density vs Code 128 | 24-143% wider for same data | Baseline |
| ISO standard | ISO/IEC 16388 | ISO/IEC 15417 |
| GS1 compliance | Not applicable | GS1-128 standard |
| Numeric-only mode | No | Yes (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.
| Payload | Code 39 width | Code 128 width | Code 39 wider by |
|---|---|---|---|
HELLO (5 uppercase chars) | 112 modules | 90 modules | +24% |
PART-12345-A (12 chars) | 224 modules | 167 modules | +34% |
1234567890 (10 digits) | 192 modules | 90 modules (Code C) | +113% |
12345678901234567890 (20 digits) | 352 modules | 145 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
| Situation | Use |
|---|---|
| New implementation, no legacy constraints | Code 128 |
| GS1 or supply chain compliance required | Code 128 / GS1-128 (mandatory) |
| All-digit serial numbers or GTINs | Code 128 (Code C mode) |
| Lowercase or mixed-case data | Code 128 |
| Trading partner specifies Code 39 by name | Code 39 |
| DoD LOGMARS / specific AIAG mandate | Code 39 |
| Asset tags, label size not constrained, uppercase only | Either (Code 39 acceptable) |
| Need lowercase, considering Code 39 Extended | Code 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.