DEV Community

Snappy Tools
Snappy Tools

Posted on

QR Codes for Developers: How They Work and How to Generate Them

QR codes are everywhere, but most developers treat them as a black box — scan, get URL, done. Understanding how they work makes you a better tool-user and opens up some genuinely useful applications.

What is a QR code?

QR (Quick Response) codes are 2D matrix barcodes invented by Denso Wave in 1994 for tracking vehicle parts. They encode data as a pattern of black and white squares arranged in a grid. Unlike 1D barcodes that only encode numbers along a single axis, QR codes encode data in two dimensions, allowing much higher data density.

A standard QR code can encode up to 4,296 alphanumeric characters or 7,089 numeric-only digits.

Anatomy of a QR code

Every QR code has the same structural elements:

Finder patterns — three square patterns in three corners. Their consistent shape lets scanners find and orient the code regardless of rotation or viewing angle.

Timing patterns — alternating black and white dots between the finder patterns. They help the decoder calculate the grid size.

Alignment patterns — smaller squares distributed through larger codes. They help correct distortion when the code is photographed at an angle.

Data area — the remaining modules (squares) encode the actual data.

Quiet zone — a white border around the entire code. Scanners need this margin to distinguish the code from its surroundings.

Error correction codewords — redundant data that allows partial damage to be recovered. There are four levels:

  • L (Low) — can recover ~7% damage
  • M (Medium) — ~15%
  • Q (Quartile) — ~25%
  • H (High) — ~30%

Higher error correction = larger QR code for the same data, but more resilient to damage.

What can QR codes encode?

QR codes encode text — but the encoding type affects how much data fits:

  • Numeric: 0–9 only. Most compact. Used for phone numbers, ticket numbers.
  • Alphanumeric: 0–9, A–Z (uppercase only), space, and $%*+-./:. More compact than binary for compatible strings.
  • Binary/byte: arbitrary bytes. Used for full UTF-8 text, URLs with lowercase letters.
  • Kanji: optimised encoding for Japanese characters.

In practice, most scanners on modern smartphones can handle anything a QR code contains, including Unicode text. But if you want maximum compatibility, keep URLs short and ASCII-only.

Common QR code use cases

URLs — the most common use. Any URL works, but shorter URLs produce smaller codes that are easier to scan.

Contact cards (vCard/MeCard) — a specific format that creates a QR code your phone's camera app recognises as a contact to save.

Wi-Fi credentials — a format that connects a phone to Wi-Fi when scanned:

WIFI:S:MyNetworkName;T:WPA;P:MyPassword;;
Enter fullscreen mode Exit fullscreen mode

Plain text — QR codes can encode any text. Useful for notes, keys, IDs.

Payment/crypto addresses — Bitcoin and most crypto wallets display QR codes to receive payments.

Generating QR codes in JavaScript

For browser-based generation, the qrcode library is lightweight and no-dependency:

<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
<div id="qr"></div>
<script>
new QRCode(document.getElementById("qr"), {
  text: "https://snappytools.app",
  width: 256,
  height: 256,
  colorDark: "#000000",
  colorLight: "#ffffff",
  correctLevel: QRCode.CorrectLevel.H
});
</script>
Enter fullscreen mode Exit fullscreen mode

For Node.js:

const QRCode = require('qrcode');

// To file
await QRCode.toFile('qr.png', 'https://snappytools.app');

// To SVG string
const svg = await QRCode.toString('https://snappytools.app', { type: 'svg' });

// To data URL (for embedding in HTML)
const dataUrl = await QRCode.toDataURL('https://snappytools.app');
Enter fullscreen mode Exit fullscreen mode

Generating QR codes in Python

import qrcode

qr = qrcode.QRCode(
    version=1,          # 1=smallest, auto-scales up as needed
    error_correction=qrcode.constants.ERROR_CORRECT_H,
    box_size=10,        # pixels per module
    border=4,           # quiet zone in modules
)
qr.add_data('https://snappytools.app')
qr.make(fit=True)

img = qr.make_image(fill_color="black", back_color="white")
img.save("qr.png")
Enter fullscreen mode Exit fullscreen mode

QR codes without writing code

If you just need a QR code for a URL, WiFi network, or text string, you can generate it in your browser without any code. The QR Code Generator supports URLs, WiFi credentials, plain text, and contact cards — generates the code as you type, with download as PNG.

Common design mistakes

Too much data — encoding a 200-character URL produces a dense code that requires a steady hand and good lighting to scan. Use a URL shortener for long URLs.

Too little quiet zone — placing the QR code flush against text or another image makes it unscannable. Always maintain a 4-module white border (4× the size of one module).

Low contrast — the code must be high contrast. Beige-on-white or light-grey-on-white will fail in poor lighting. Black-on-white is always safest.

Adding a logo without increasing error correction — putting a logo in the centre works because error correction can recover the obscured data — but only at level H (30%). If you embed a logo, set error correction to H.

Testing your QR codes

Always test generated QR codes before printing or deploying. Test with:

  1. A phone camera's native QR scanner (not an app)
  2. A different phone model
  3. From the expected scan distance
  4. Under realistic lighting conditions

Print a test batch and scan from a printout — screen reflections and resolution differences mean a code that scans fine on-screen may fail in print.


QR codes are deceptively simple at the use-it level. Understanding the error correction levels, data encoding modes, and design constraints takes you from "use a library" to "reason about what's actually possible" — which matters when you're embedding logos, printing at small sizes, or encoding non-ASCII text.

Top comments (0)