MostlyQR

How small can a QR code be printed? The sizes, computed

There is no single minimum size for a QR code. We ran five real payloads through our own encoder for the module counts, then turned those into millimetres.

Max Čelar··Printing & scanning

What’s new here: Symbol version and module count for five real payload types at all four error-correction levels, computed with the encoder MostlyQR ships, then converted to printed millimetres — so the minimum size is derived from your payload instead of quoted as one blanket number.

Every guide to printing QR codes gives you a single number. Two centimetres. One inch. Three centimetres for packaging. Those numbers are guesses dressed up as standards, and they are wrong in both directions: too big for a short link on a business card, dangerously too small for a vCard on a bottle label.

The real answer is a division, and you can do it before you print anything.

# Why there is no single minimum size

A QR code is not a picture that gets smaller. It is a grid of modules — the little squares — and the number of modules is fixed by your payload, not by you. Twenty-one characters of short link needs a 25×25 grid. A vCard with a name, a phone number and an email needs 49×49. Print both at 25mm and you have printed two very different things: in the first, each module is 0.76mm across; in the second, 0.44mm.

The module is what the printer has to hold and the camera has to resolve. So the question “how small can my QR code be” is really “how small can one module be, and how many of them do I have” — and the second half is computable.

# What your payload costs in modules

We ran five payload types through the encoder MostlyQR actually ships (buildMatrix in our packages/qr, which wraps the MIT node-qrcode library) at all four error-correction levels. The number after the slash is the grid size — the modules across one side, not counting the quiet zone.

Payload Characters EC L EC M EC Q EC H
short link 21 v2 / 25 v2 / 25 v2 / 25 v3 / 29
Wi-Fi join (WPA) 47 v3 / 29 v4 / 33 v4 / 33 v6 / 41
campaign URL with UTM tags 87 v5 / 37 v6 / 41 v7 / 45 v9 / 53
long product URL 116 v6 / 41 v7 / 45 v9 / 53 v10 / 57
vCard (name, org, phone, email, URL) 135 v6 / 41 v8 / 49 v9 / 53 v11 / 61

These are the exact strings, so you can reproduce every row:

text
https://mqr.sh/AB12CD
WIFI:T:WPA;S:CafeGuest;P:coffee-and-cake-2026;;
https://example.com/spring-menu?utm_source=poster&utm_medium=qr&utm_campaign=spring2026
https://example.com/collections/spring-2026/products/heirloom-tomato-seed-pack-organic?variant=4471029&ref=packaging
BEGIN:VCARD ⏎ VERSION:3.0 ⏎ N:Celar;Max ⏎ FN:Max Celar ⏎ ORG:MostlyQR ⏎
TEL:+3861234567 ⏎ EMAIL:max@mostlyqr.com ⏎ URL:https://mostlyqr.com ⏎ END:VCARD

The spread is the point. Across ordinary, everyday payloads the grid runs from 25 to 61 modules a side — a factor of 2.4 in linear density, before anyone has chosen a paper size.

# If you check this table, check it with the strings

Character count alone will not reproduce those numbers, and it is worth knowing why before you conclude we got them wrong.

A QR encoder does not treat every character as a byte. It picks an encoding mode per run of characters — numeric (3⅓ bits per digit), alphanumeric (5½ bits, but only for digits, uppercase letters and a handful of symbols), or byte (8 bits) — and a good encoder splits one payload into several segments to get the cheapest total. Ours does. Here is what it actually chose:

Payload Segments
short link Byte:14 + Alphanumeric:7
Wi-Fi join Alphanumeric:10 + Byte:37
campaign URL Byte:83 + Numeric:4
long product URL Byte:95 + Numeric:7 + Byte:14
vCard Alphanumeric:11 + Byte:1 + Alphanumeric:11 + Byte:44 + Numeric:10 + Byte:49 + Alphanumeric:9

Encode the same character counts as a single byte run instead and you get a different, larger table — v3/29 for the short link at level Q rather than v2/25, and v7/45 for the vCard at level L rather than v6/41. Both tables are correct; they describe different payloads.

Which hands you a free lever, if your short links use an uppercase slug. https://mqr.sh/AB12CD splits into byte + alphanumeric because the scheme and host are lowercase. Write the whole URL uppercase — HTTPS://MQR.SH/AB12CD — and it becomes one 21-character alphanumeric segment: at level L that is v1, 21 modules, a whole version smaller than the mixed-case form. (At levels M and Q this particular string stays at v2/25 — it is already benefiting from the alphanumeric tail; the gain shows up at L, and it grows with the length of the uppercase run.) Scheme and host are case-insensitive so the URL resolves identically; the path is not, so this only works if your slug is genuinely uppercase. Ours are.

# The same 25mm, five different codes

Now fix the printed width and read off what each payload leaves you. This is (width ÷ (modules + 8)), the 8 being the mandatory four-module quiet zone on each side:

Payload EC M module size at 25mm EC H module size at 25mm
short link 0.76mm 0.68mm
Wi-Fi join 0.61mm 0.51mm
campaign URL with UTMs 0.51mm 0.41mm
long product URL 0.47mm 0.38mm
vCard 0.44mm 0.36mm

Same square on the page. Twice the feature size at one end of the table as the other. A print shop that is comfortable holding 0.5mm cleanly will produce a perfect short-link code and a marginal vCard from the identical layout.

# The minimum width, from the other direction

Most people arrive with the opposite question: not “what do I get at 25mm” but “how small can I go”. Pick a module size your printing process can actually hold — 0.5mm is a common floor for offset and decent digital printing on coated stock — and the width follows:

Payload EC M EC H
short link 16.5mm 18.5mm
Wi-Fi join 20.5mm 24.5mm
campaign URL with UTMs 24.5mm 30.5mm
long product URL 26.5mm 32.5mm
vCard 28.5mm 34.5mm

That is the range the internet compresses into “about 2cm”. At the ends of it, 2cm is either 20% larger than you need or 40% smaller than you can get away with.

If your printer will hold 0.33mm — fine screen printing, good digital, no absorbent stock — divide these by 1.5. If you are printing on corrugated card, fabric or anything that spreads ink, go the other way and assume 1mm.

# The biggest lever is the URL, not the printer

Look again at the first table. The short link and the long product URL are the same information — they both take someone to the same page — and one of them is 25 modules while the other is 45.

That is the whole game. Every millimetre of module size you buy by arguing with your printer, you can get for free by shortening what the code encodes. A dynamic short link is 21 characters no matter how long the destination is, and it has a second advantage that matters more on a print run: you can change where it points after the ink is dry, so a code that outlives its landing page does not become a dead end.

For anything that will be printed small — a business card, a label, the corner of a menu — encode a short link and redirect. Encoding the full campaign URL with its UTM tags directly into the code costs you 16 modules a side and buys nothing a redirect cannot do better.

# What error correction costs you in size

Error correction adds redundancy so a damaged or partly covered code still reads. It is not free, and the tables above price it:

  • short link, M → H: 25 → 29 modules (+16% linear)
  • Wi-Fi join, M → H: 33 → 41 (+24%)
  • vCard, M → H: 49 → 61 (+24%)

A quarter more width, for a code that survives being scuffed, printed on packaging, or partly covered by a logo. On a poster, where space is free, take level H and stop thinking about it. On a label where 30mm is all you have, level M with a short link beats level H with a long URL — the shorter payload is carrying more of the robustness than the extra error correction would.

If you are covering the middle with a logo, the trade-off shifts hard toward H, and there is a measured budget for how big the logo can be.

# What this does not measure

Everything above is about the symbol. It is arithmetic over an encoder, it is exact, and you can re-run it. It is also only half of what decides whether a printed code scans:

  • We did not test scanning distance with real cameras. The industry rule of thumb — the code’s width should be roughly a tenth of the distance you want to scan it from — is widely cited and we have not verified it. Treat it as a starting point for posters and signage, not as a measurement.
  • Ink spread, substrate and contrast are not in the numbers. A 0.4mm module on coated card and a 0.4mm module on corrugated board are not the same module.
  • Camera quality varies enormously. A five-year-old phone in a dim restaurant is the real test, and it is the one you should actually run: print the code at the size you intend, on the stock you intend, and scan it with the worst phone in the office.

That last one is not a caveat, it is the advice. The arithmetic tells you which sizes are worth testing. The test tells you whether it works.

# Re-running this yourself

Every table above is printed by a script rather than typed into the article, and the script is in the repository at draft/mostlyqr/seo/benchmarks/print-size.js. It runs buildMatrix over the five strings above, dumps the encoding-mode segments, prints the byte-mode control table next to the real one, and derives the millimetre figures. If any number here is wrong, that file is where it is wrong.

# The short version

  1. Encode a short link, not the full URL — it is the only lever that changes the grid instead of the paper.
  2. Look up your payload’s module count above, or compute it.
  3. Multiply (modules + 8) by the smallest module your printing process holds cleanly. That is your minimum width. (If you are laying the code into one of our templates, a poster at A3 and a flyer at A4 both leave far more room than any payload here needs.)
  4. Print it at that size, on the real stock, and scan it with a bad phone.

If you want the code to carry a picture as well as data, the size question gets sharper still — a photograph needs a much denser grid to be visible at all, which we measured separately for photo QR codes.

Frequently asked questions

What is the minimum size for a QR code?

There isn't one number. The code is a grid of modules, and how many modules it needs depends entirely on how much data you put in it. A short link at error-correction level M is 25 modules across; the same code carrying a vCard is 49. Printed at the same width, the second one's modules are almost half the size — so one of them scans at 17mm and the other does not. Work out your module count first, then pick a width.

Does a longer URL make the QR code bigger?

It makes it denser, which amounts to the same thing. In our measurements a 21-character short link encodes to 25 modules at level M, and a 116-character product URL to 45. Print both 25mm wide and the modules are 0.76mm and 0.47mm respectively. Shortening the URL is the cheapest way to make a code printable small — it costs nothing and it is the one lever that changes the grid rather than the paper.

Does higher error correction make the code bigger?

Yes, and by more than most people expect. Going from level M to level H added between 4 and 12 modules per side across all five payloads — for the vCard, 49 modules became 61, which is a 25% increase in the linear size you have to print. Level H is usually worth it if the code will be handled, printed on packaging or partly covered by a logo, but it is a size decision, not a free upgrade.

How much white space does a QR code need around it?

Four modules on every side. That quiet zone is part of the symbol, not decoration — readers use it to find the edges — so it belongs in the arithmetic. Every printed width in this article is computed as (modules + 8) × module size for exactly that reason.

Sources
  1. QR Code standardization (ISO/IEC 18004) — Denso Wave
  2. node-qrcode (the MIT encoder our matrix builder wraps)
More in this topic