Code 39 and Code 128 are both linear alphanumeric barcodes. On a label they look nearly identical. In almost every technical dimension - character set, density, check digit reliability, standards compliance - Code 128 is the better format. Yet 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), making it one of the oldest barcodes still in active production use. The name "3 of 9" comes from its physical structure: each character is encoded as 9 elements (5 bars and 4 spaces), exactly 3 of which are wide. The pattern of which 3 are wide uniquely identifies each character. This binary wide/narrow structure was a deliberate design choice for the printing technology of the era - it is more tolerant of ink spread and press variation than systems that rely on precise multi-width elements.
Code 39 encodes exactly 43 characters:
- 26 uppercase letters (A-Z)
- 10 digits (0-9)
- 1 space
- 6 symbols: hyphen
-, period., dollar sign$, forward slash/, plus sign+, percent sign%
No lowercase letters. No exclamation marks, colons, at-signs, or brackets. The asterisk (*) is the start/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 used, it employs Mod 43 arithmetic (assign each character a value 0-42, sum the values, mod 43 gives the check character). The optional nature is a well-known source of operational headaches: a Code 39 printed with a check digit enabled, scanned by a reader configured with check digit verification off, returns the trailing check character as an extra letter in the data string. Your application rejects it. These mismatches between encoder and scanner configuration are entirely avoidable but surprisingly common in legacy environments.
Code 128: the modern standard
Code 128 was invented in 1981 by Computer Identics and is now standardized as ISO/IEC 15417. The name refers to the full 128 ASCII characters it can encode. It is the foundation of GS1-128, which is the global standard for shipping labels (UPS, FedEx, USPS), pharmaceutical serialization, and retail supply chains worldwide.
Code 128 has three sub-modes that a single symbol can switch between mid-stream:
- Code A: ASCII 0-95, including control characters (null, tab, linefeed) and uppercase letters. Used when control characters are needed in the payload.
- Code B: ASCII 32-127, all printable characters including lowercase. The default mode for alphanumeric content.
- Code C: numeric pairs - encodes two decimal digits (00-99) per single codeword. For all-digit payloads this produces roughly half the symbol length of Code A or B. A 20-digit serial number in Code C is dramatically shorter than the same number in Code 39.
A good encoder automatically selects the optimal mode or switches between modes mid-symbol. The encoder in bwip-js, which powers Barcode Press, does this automatically.
Code 128's check character is mandatory and automatic. It is a mod-103 weighted sum of all codewords, embedded in the symbol structure, and verified by the scanner on every read. Unlike Code 39's optional Mod 43 check, there is no configuration decision to make - it is always there, always verified, and transparent 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 is Code 128? Actual measurements
The density difference is real and significant. The table below shows actual 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% |
The commonly quoted figure of "30-50% shorter" applies to mixed uppercase alphanumeric content. For numeric-only data, Code 128 using Code C mode 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, this is not a marginal difference.
Code 39 Extended: a dead end
Code 39 Extended (sometimes called Full ASCII Code 39) encodes all 128 ASCII characters by using shift pairs from the base 43-character set. Each extended character requires two Code 39 codewords instead of one - roughly doubling the symbol width for mixed-case content.
Do not use it. Code 39 Extended is wider than Code 128 for the same data, requires explicit scanner configuration to decode, and is not universally supported on older hardware. If you need lowercase letters or full ASCII, the answer is Code 128, not Code 39 Extended. There is no scenario where Code 39 Extended is preferable.
GS1-128: why supply chains standardized on Code 128
GS1-128 is the Application Identifier standard built on top of Code 128. Two- to four-digit AI codes in parentheses prefix structured data: (01) for GTIN, (17) for expiry date, (10) for lot number, (00) for SSCC (Serial Shipping Container Code), and dozens of others. A single GS1-128 barcode can encode a product identifier, expiry, lot, and serial number in a compact, machine-readable format that scanners anywhere in the world can interpret correctly.
GS1-128 is mandatory for shipping labels from UPS, FedEx, and USPS, required for pharmaceutical serialization under FDA and EU regulations, and the standard for retail supply chain compliance globally. It requires Code 128 as its underlying symbology. There is no GS1-39. If any part of your supply chain involves GS1 compliance, Code 128 is not a choice - it is a prerequisite.
Why Code 39 is still everywhere
Code 128 has been objectively superior since 1981. Code 39 persists for three reasons that have nothing to do with technical merit:
Legacy system 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 requires revalidating every reader in every warehouse and every downstream data system. For a stable product line with thousands of existing labels in circulation, the migration cost is real and the benefit is modest. "Good enough" beats "better" in mature operations.
Industry mandates that predate Code 128. The US Department of Defense standardized on Code 39 for LOGMARS (Logistics Applications of Automated Marking and Reading Symbols, MIL-STD-1189) before Code 128 existed. The Automotive Industry Action Group (AIAG) published labeling standards specifying Code 39 that some suppliers are still contractually bound to follow. These standards update slowly.
Implementation simplicity. Code 39 can be implemented with a lookup table and no mandatory check digit calculation - relevant in the 1970s and 1980s for embedded label printers with minimal computing resources. Irrelevant for any modern system, but 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 - never Code 39 Extended |
The rule is simple: use Code 128 unless something external forces you to use Code 39. The density, character set, and mandatory check digit are all advantages you get for free. If you are starting fresh and there is no mandate, there is no reason to choose Code 39.