Code 39 vs. Code 128: Which to Use for Internal Labels
Should I use Code 39 or Code 128 for my inventory, bin, and asset labels?
Short answer
For new internal labels, use Code 128. It encodes upper- and lowercase text, makes shorter barcodes for the same data, and always includes a check character. Choose Code 39 only when an existing system, customer or scanner setup specifically expects it, and then keep your IDs within its 43-character set.
On this page
You're labeling bins, shelves, tools or equipment that only your own team will scan. No retailer or GS1 rule tells you which barcode to use, and your label software offers both Code 39 and Code 128. Both are linear barcodes that handle letters and numbers, and both read on ordinary handheld scanners.
The differences show up in label width, in what characters you can use, and in how errors get caught. This comparison walks through each one so you can pick once and stay consistent.
Code 39 and Code 128 side by side
| Code 39 | Code 128 | |
|---|---|---|
| Standard | ISO/IEC 16388 | ISO/IEC 15417 |
| Characters, default mode | 43: A–Z, 0–9, space and - . $ / + % | All 128 ASCII characters, upper- and lowercase |
| Lowercase letters | Only in Full ASCII mode, which the scanner must support | Built in (code set B) |
| Numbers | One digit per character | Two digits per character in code set C |
| Check character | Optional (mod 43) | Always present (mod 103) |
| Start and stop | Asterisk (*) at both ends | Dedicated start and stop characters |
| Bar widths | Two widths, wide-to-narrow ratio 2:1 to 3:1 | Four widths, fixed ratio |
| Label width for the same data | Longer | Shorter |
Both symbologies are variable length, meaning you can encode a short or long ID without padding it to a fixed size.
Character sets: what fits in each
Code 39's basic set is 43 characters: the digits, uppercase letters, space, and six symbols. Each message also starts and ends with an asterisk, which Zebra's ZPL guide notes the printer adds automatically. An ID like TOOL-0417 or BIN A12 fits fine. One like Bin-a12 does not, because of the lowercase letters.
Code 39 has a Full ASCII variant that reaches all 128 ASCII characters by pairing characters, so a lowercase letter takes two symbol characters. The catch is that the scanner has to have Full ASCII turned on to decode those pairs correctly. On Zebra's RS6100 scanner, for example, it's disabled by default.
Code 128 handles all of this natively. Code set B covers upper- and lowercase letters, digits and punctuation, and the encoder switches sets as needed without any scanner configuration.
The simplest fix is to design IDs that suit both: uppercase letters, digits and hyphens. That keeps your options open if you ever change symbologies.
Label width: a worked comparison
Width matters because a shorter barcode lets you use a larger bar size on the same label, and larger bars are easier to print and scan. Here's how the two compare for the same data.
How each one is built. A Code 39 character has nine elements, five bars and four spaces, and three of them are wide. At a 3:1 wide-to-narrow ratio, that's 15 modules per character, plus a gap between characters, typically one module. A Code 128 character is always 11 modules, and the start, check and stop characters add 35 modules in total, per the GS1 General Specifications.
Example 1: TOOL-0417. This is nine characters of data.
| Symbology | Characters encoded | Width in modules |
|---|---|---|
| Code 39, 3:1 ratio | TOOL-0417 (11) | 11 × 15 + 10 gaps = 175 |
| Code 39, 2:1 ratio | TOOL-0417 (11) | 11 × 12 + 10 gaps = 142 |
| Code 128 | Start B, TOOL-, Code C, 04, 17, check, stop | 10 × 11 + 13 = 123 |
At a 0.010-inch module (10 mil), that's about 1.75, 1.42 and 1.23 inches before quiet zones. Code 128 saves about 30% over Code 39 at 3:1.
Example 2: a 10-digit asset number, 1000004178. Code 39 at 3:1 needs 12 characters, or 12 × 15 + 11 gaps = 191 modules. Code 128 uses code set C, packing the digits into five characters: 11 × 5 + 35 = 90 modules. That's less than half the width.
The more digits your IDs contain, the bigger Code 128's advantage. For purely numeric asset or serial numbers, it's not close.
Check characters and scanner settings
Code 128: always on
Every Code 128 symbol carries a mod-103 check character. Zebra's ZPL guide says it is always there and can't be turned on or off. The scanner verifies it automatically, and you never see it in the human-readable text. Our Code 128 explainer works through the calculation.
Code 39: optional, and the scanner must agree
Code 39 has an optional mod 43 check character. To calculate it, give each character its value (0–9 for digits, 10–35 for A–Z, then 36 to 42 for the hyphen, period, space and other symbols), add them up, and take the remainder after dividing by 43. Zebra publishes the value table.
For TOOL-0417, the values are T 29, O 24, O 24, L 21, hyphen 36, 0, 4, 1 and 7. They add up to 146, and 146 divided by 43 leaves a remainder of 17, which is the letter H. The barcode encodes TOOL-0417H.
The check character only helps if the scanner is told to expect it. On Zebra's RS6100, Code 39 check digit verification is disabled by default. With verification off, the scanner can't tell the H is a check character, so it passes TOOL-0417H to your software as if it were part of the ID. Either configure every scanner consistently or skip the Code 39 check character.
Without a check character, Code 39 still has some built-in protection. Every character must have exactly three wide elements out of nine, so many misreads produce an invalid pattern and get rejected. A check character adds a second layer that Code 128 always has.
When Code 39 still makes sense
Code 128 is the better default for new labels, but Code 39 is the right call in a few situations:
- An existing system expects it. If your warehouse software, existing labels or scanners were set up for Code 39, matching them beats mixing two symbologies on the same shelves.
- A customer or industry spec requires it. Zebra's printer documentation describes Code 39 as a standard in many industries. If a customer's label specification names Code 39, follow it.
- You're printing from a font. Code 39 can be printed from a barcode font by wrapping the text in asterisks, because it needs no code-set logic or required check character. Code 128 fonts need an encoder to build the start, check and stop characters. Our guide to barcodes in Excel and Google Sheets explains both approaches.
If none of those apply, there's little reason to choose Code 39 today.
Bottom line
Use Code 128 for new bin, shelf and asset labels. It gives you shorter barcodes for the same ID, lowercase support without scanner tweaks, and a check character that is always on. Pick Code 39 only to match an existing system, a customer's spec, or a font-based workflow, and keep your IDs to uppercase letters, digits and hyphens either way. You can make both in the barcode generator; print one of each with a real ID and compare them on your actual label stock.
Sources
- ISO: ISO/IEC 16388:2023 Information technology — Automatic identification and data capture techniques — Code 39 bar code symbology specification
- ISO: ISO/IEC 15417:2007 Information technology — Automatic identification and data capture techniques — Code 128 bar code symbology specification
- GS1: GS1 General Specifications Standard
- Zebra Technologies: ^B3 — Code 39 Barcode
- Zebra Technologies: ^BC — Code 128 Barcode (Subsets A, B, and C)
- Zebra Technologies: Mod 43 Check Digit
- Zebra Technologies: Code 39 Check Digit Verification
- Zebra Technologies: Code 39 Full ASCII Conversion