How QR Codes Work — and How to Make Ones That Actually Scan
QR codes aren't magic. Finder patterns, Reed-Solomon error correction, version sizing — plus practical rules for making QR codes that scan reliably.
A QR code is a matrix barcode. Scan one with any smartphone camera and in under a second it decodes a URL, contact card, Wi-Fi credential, or plain text. They look like random noise but every module — every black or white square — has a defined role. Understanding the structure makes you better at generating QR codes that scan reliably and don’t fail in the field.
Use the QR Code Generator on this site to generate codes while you read — try changing the error correction level and watch the code density change.
The anatomy of a QR code
A QR code is a square grid. Every square in the grid is a module (not a “pixel” — the QR spec calls them modules). Modules are either dark or light, encoding a 1 or 0. The grid is surrounded by a quiet zone — a mandatory margin of white space that lets scanners find where the code begins.
Finder patterns
The three large square-in-a-square patterns in the top-left, top-right, and bottom-left corners are finder patterns. They are always 7×7 modules: a 3×3 dark square, surrounded by a ring of light modules, surrounded by a ring of dark modules.
The scanner uses finder patterns to locate the QR code in a camera frame, determine its orientation, and correct for perspective distortion. The pattern is designed so that no naturally occurring image produces the same 1:1:3:1:1 ratio of dark:light:dark:light:dark in any direction. This is why scanners find QR codes reliably at angles.
Alignment patterns
Larger QR codes (Version 2 and above) add alignment patterns — smaller 5×5 squares scattered across the code. They help scanners correct for curved or distorted surfaces. A code on a cylindrical bottle has more alignment patterns than a code on a flat poster.
Timing patterns
Running between the finder patterns are timing patterns — alternating dark and light modules in a single row and column. They establish the module grid spacing, allowing the scanner to count modules even if the image is slightly blurry or distorted.
Format information
Two strips near the finder patterns encode format information: the error correction level (L/M/Q/H) and the mask pattern applied to the data. Format information is stored twice — masked twice differently — so if one copy is damaged, the scanner can use the other.
Data modules
Everything else — roughly 70–80% of the modules in a typical code — is data. It’s read in a zigzag pattern from the bottom-right corner upward, in 2-module-wide columns, avoiding the functional patterns.
The version system
QR code version controls the grid size. Version 1 is 21×21 modules. Each version up adds 4 modules per side. Version 40 is 177×177 modules.
| Version | Grid size | Max alphanumeric chars | Max binary bytes |
|---|---|---|---|
| 1 | 21×21 | 25 | 17 |
| 5 | 37×37 | 106 | 72 |
| 10 | 57×57 | 271 | 187 |
| 20 | 97×97 | 772 | 535 |
| 30 | 137×137 | 1520 | 1059 |
| 40 | 177×177 | 4296 | 2953 |
The QR encoder picks the minimum version that fits your data at the chosen error correction level. This is why longer URLs produce visually denser, harder-to-scan codes — they require a higher version with more modules, which means smaller modules at the same physical print size.
The practical implication: keep your URLs short. A short URL like https://xbt.dev/p/abc fits in Version 3 with high error correction. A full tracking URL with UTM parameters may require Version 15 or higher, producing a much denser code.
Data encoding modes
The QR spec defines four encoding modes for different character sets:
| Mode | Chars per module | Use for |
|---|---|---|
| Numeric | 10 bits per 3 digits | Digit-only strings |
| Alphanumeric | 11 bits per 2 chars | A-Z, 0-9, space, $, %, *, +, -, ., /, : |
| Byte | 8 bits per char | UTF-8, arbitrary binary |
| Kanji | 13 bits per char | Shift-JIS double-byte characters |
Numeric mode is the most efficient — a phone number packs tightly. Byte mode handles URLs and arbitrary content but is less efficient. A QR encoder picks the mode (or mixes modes) to minimize version required.
One subtlety: uppercase URLs use alphanumeric mode and are more efficient than lowercase URLs. HTTPS://XEROBIT.DEV/TOOLS/QR-CODE-GENERATOR/ encodes more efficiently than https://xerobit.dev/tools/qr-code-generator/. QR scanners handle both; whether the efficiency gain matters depends on whether you’re optimizing for the smallest possible code.
Reed-Solomon error correction
This is the part that makes QR codes remarkable. Reed-Solomon is a forward error correction algorithm originally developed for deep-space communication. In a QR code, it adds redundant data that lets the scanner recover the original message even when part of the code is obscured or damaged.
Error correction levels
| Level | Name | Recovery capacity | Relative code density |
|---|---|---|---|
| L | Low | ~7% of data modules | Smallest, most data |
| M | Medium | ~15% | Default for most uses |
| Q | Quartile | ~25% | Good for industrial printing |
| H | High | ~30% | Largest, least data capacity |
At Level H, 30% of the code can be destroyed and the scanner still recovers the full data. This is why you can put a logo in the center of a QR code and it still scans — the logo covers modules, but if the data lost is within the error correction budget, Reed-Solomon reconstructs it.
The tradeoff: higher error correction requires more redundancy modules, which requires a higher version for the same data, producing a larger, denser code. For a URL printed at adequate size on clean white paper, Level M is the right choice. For a URL that will be laser-etched onto metal or printed on a coffee cup that will get wet and scratched, use Level H.
How Reed-Solomon works (briefly)
The data bytes are treated as coefficients of a polynomial over a finite field (GF(256) for QR codes). The generator polynomial for the chosen error correction level produces a set of error correction codewords — extra bytes appended to the data. The decoder evaluates the polynomial and can solve for up to t corrupted bytes if it has 2t error correction codewords. QR Level H generates enough codewords for t = 15% of the total codeword count.
You don’t need to implement this yourself — every QR library handles it. What you do need to know is which level to choose.
How to make a QR code that scans reliably
Size minimums
The smallest practical print size for a QR code is 2cm × 2cm (roughly 0.8 inches square). Below this, the modules are too small for most smartphone cameras to resolve at typical scanning distances. For outdoor signage or codes that will be scanned from a distance, scale up proportionally — a sign you’ll scan from 1 meter away needs at least 5cm.
The ISO/IEC 18004 standard specifies a minimum module size of 0.25mm for machine-scanning, but smartphones are not calibrated industrial scanners. Use 2cm as your minimum for consumer scanning scenarios.
The quiet zone
The quiet zone is mandatory. ISO/IEC 18004 specifies a minimum of 4 module-widths of white space on all four sides. In practice: leave at least 4–8 modules of white space. If a QR code is flush against a border, printed text, or another graphic element, it will fail to scan because the scanner can’t locate the finder patterns.
Contrast
Dark modules on a light background is the standard. Minimum contrast ratio: 4:1 between the dark and light modules. Black on white is ideal; dark navy on off-white works. Light grey on white fails. Inverting the colors (light modules on a dark background) may fail on some older scanners.
Avoid putting QR codes on busy photographic backgrounds. Even with high error correction, if the scanner can’t resolve the modules because of background noise, no amount of Reed-Solomon helps.
Error correction level recommendations
| Use case | Recommended level |
|---|---|
| Digital display (screen) | L or M |
| Clean print, white paper | M |
| Print with a logo overlay | H |
| Industrial, outdoor signage | Q or H |
| Laser etching, embossing | H |
| T-shirt printing | Q or H |
Color QR codes
You can use color — brands frequently do — but follow these rules:
- Dark color on a light background, not the reverse.
- Maintain at least 4:1 contrast ratio between the dark and light modules.
- Don’t use red as the dark color. Early camera sensors have weak red channel sensitivity; red-on-white codes scan poorly on older devices.
- Avoid gradients within the code area.
What to embed: URL best practices
For almost every use case, embed a URL. Not the raw destination URL — a short redirect URL you control.
Why not embed the destination URL directly
A direct destination URL is static. If the page moves, the QR code breaks. If you add UTM parameters later, you can’t update the QR code in the field. If you want to A/B test two landing pages, you can’t.
A short redirect URL lets you update the destination from your server without reprinting anything. This is the core difference between static and dynamic QR codes.
Static vs dynamic QR codes
Static QR code: the full data is encoded in the modules. Once printed, the content cannot change. Good for: Wi-Fi credentials that don’t change, vCards, simple text, one-time use codes.
Dynamic QR code: encodes a short redirect URL. The actual destination is stored in a database on a server. Change the destination by updating the database; the physical QR code stays the same. Good for: marketing campaigns, product packaging, menus, anything printed at scale or likely to need updates.
The “dynamic” isn’t in the QR code itself — it’s in the redirect infrastructure. The QR code still encodes a static URL; that URL just happens to redirect to wherever you point it.
Dynamic QR codes add a dependency: if your redirect service is down, the QR code doesn’t work. Don’t use a free third-party QR redirect service for anything critical — host your own short-link redirects or use a provider with an SLA.
Keep the embedded URL short
Shorter URLs:
- Require fewer modules (lower version)
- Produce a less dense, easier-to-scan code
- Leave more budget for error correction
- Look less intimidating to users who inspect the URL before tapping
Use HTTPS — HTTP URLs trigger browser warnings and some scanning apps flag them as suspicious. A URL of https://yourdomain.com/q/abc123 is better than https://yourdomain.com/products/category/item?utm_source=print&utm_medium=flyer&utm_campaign=spring_2026.
Testing before deployment
Before printing 10,000 units with a QR code, test with at least three different devices:
- An iPhone (current model)
- An Android phone (mid-range, not flagship)
- An older device (2–3 years old) if your audience is consumer-facing
Test at the actual size the code will be printed. Test in the actual lighting conditions it will be scanned in. Test if there’s a lamination layer (laminate reduces contrast and adds glare).
Scan the code without focusing — let auto-focus find it. If the scanner requires you to hold still for more than 2 seconds, the code is too dense or too small for the context.
The QR Code Generator generates codes in SVG (for print) and PNG (for digital). Use SVG for print — it scales to any size without pixelation, so your print vendor can output it at 300+ DPI.
Further reading
- QR Code Generator — generate QR codes with configurable error correction, size, and format
- ISO/IEC 18004:2015 — the QR code specification
- Reed-Solomon Codes for Coders — accessible walkthrough of the math behind Reed-Solomon error correction
Related posts
- Create QR Code — Generate QR Codes for URLs, Text, and Contacts — Creating a QR code takes your URL, text, or contact data and encodes it as a sca…
- Dynamic QR Code vs Static QR Code — What's the Difference? — Dynamic QR codes use a redirect URL that can be changed after printing. Static Q…
- Free QR Code Generator — Generate QR Codes with No Signup, No Watermark — Most 'free' QR code generators require signup, add watermarks, or only give you …
Related tool
Generate QR codes for URLs, text, Wi-Fi, contact cards. Custom size, colors, error correction. Download as PNG or SVG. 100% client-side.
Written by Mian Ali Khalid. Part of the Dev Productivity pillar.