# Deterministic QR generation

> QR generation is fully deterministic: given the same data, version, error correction level and mask-selection rules, the standard produces exactly one symbol. Differences between libraries come from different defaults, not randomness. Determinism is a feature, byte-identical output makes QR images cacheable, diffable and safe to snapshot-test in CI.

Source: https://useqr.app/docs/spec/deterministic-qr-generation · Last reviewed 2026-08-21 · UseQR is free forever, no signup.

---

## No dice anywhere in the pipeline

Every stage of [QR encoding](/docs/spec/how-qr-codes-are-generated) is a pure function of
its inputs:

- **Mode selection** follows from the characters in the data.
- **Version selection** is "the smallest version that fits": a lookup, not a choice.
- **Bit stream, padding, Reed–Solomon, interleaving** are all fixed arithmetic; even the
  pad bytes are the mandated constants `11101100` and `00010001`.
- **Mask selection**, the step that *looks* like an aesthetic judgement, is defined as an
  exhaustive scored search: apply all eight masks, total the four
  [penalty rules](/docs/spec/mask-selection-penalty-scores), keep the lowest. Same matrix
  in, same mask out, every time.

So the standard guarantees: **the same data, at the same version and error correction
level, encoded with the same mode segmentation and mask scoring, is the same symbol**,
module for module, today and in ten years. Generate `https://example.com` twice, or on
two machines, and you get identical matrices.

## Then why do generators differ?

Because "the same options" is doing quiet work in that sentence. Libraries legitimately
differ in defaults (error correction level, minimum version, how they split the data
into mode segments), and occasionally in mask-scoring interpretation, and any of those
shifts the output while still producing a perfectly valid, correctly decoding code. The
taxonomy of legal differences (and the differences that are actually bugs) is on
[why two generators produce different codes](/docs/spec/why-two-generators-produce-different-codes).

Within one implementation, though, determinism should extend beyond the matrix to the
**bytes of the output file**. UseQR's renderer is deliberately deterministic end to end:
identical input and style options produce an identical SVG string: same path order, same
attribute order, no timestamps, no random IDs. That is a property worth demanding from
any generator you automate against.

## Why this is a feature, not trivia

**Caching.** If the same request always yields the same bytes, QR images are perfectly
cacheable: an `ETag` is just a hash of the inputs, CDNs can cache forever, and
regeneration is free of cache-busting noise. The serving patterns are on
[caching and CDN strategy for QR images](/docs/developers/caching-and-cdn-strategy-for-qr-images).

**Testing.** Deterministic output makes QR generation snapshot-testable: commit the
expected SVG, fail CI on any byte change. A diff then *means* something, a dependency
bump that alters output gets caught at review instead of in production. Patterns in
[QR codes in CI and automated testing](/docs/developers/qr-codes-in-ci-and-automated-testing).

**Content addressing.** Hash-of-inputs equals hash-of-output, so codes can be stored and
deduplicated content-addressably: [batch runs](/bulk) with repeated payloads collapse to
one asset.

**Auditability.** Given the payload and options, anyone can regenerate the exact symbol
and confirm a printed code matches what was approved, no trust in a stored image
required.

The one caveat: determinism is per-implementation-version. A library update that changes
a default or fixes a scoring subtlety changes output legally. Pin generator versions where
byte-stability matters, and treat [/validate](/validate) (does it decode to the right
string), as the invariant that must survive upgrades, with byte equality as the stricter,
opt-in contract.

## FAQ

### Will the same text always produce the same QR code?
From the same generator with the same settings, yes, every encoding step, including mask selection, is deterministic. Across different generators the symbol may differ legally because defaults differ, while still decoding to identical text.

### Is there any randomness in QR code generation?
None. The apparent noise of the module pattern comes from the data, the Reed–Solomon codewords and the XOR mask, all computed by fixed rules. The standard's mask selection is a scored exhaustive search, not a random pick.

### Why does determinism matter for QR codes?
It makes output cacheable (same input, same bytes, cache forever), testable (snapshot the exact file in CI) and auditable (anyone can regenerate and compare against the printed code). Services with nondeterministic output forfeit all three.

### Can a library update change my QR codes?
Yes, legally, a changed default or refined mask scoring alters the symbol while remaining valid. Pin the generator version where byte-identical output matters, and always keep a decode test so upgrades prove they still encode the right data.

## Try it

- https://useqr.app/url
- https://useqr.app/validate
- https://useqr.app/bulk
