# QR code SVG path structure

> A QR code becomes SVG as path data on a square grid. UseQR merges every dark module into one path element with a single fill, uses integer coordinates at eight pixels per module, and sets shape-rendering to crispEdges on square styles — which is why the output has no anti-aliasing seams between modules.

Source: https://useqr.app/docs/spec/qr-code-svg-path-structure · Last reviewed 2026-08-21 · UseQR is free forever, MIT licensed, no signup.

---

## Two ways to draw the same matrix

Given a matrix of dark modules, an SVG generator has a choice:

**One `<rect>` per module.** Simple to emit, miserable to use: a version 5 code has around
700 dark modules, so the file carries ~700 elements, each independently styled, parsed and
rendered. Design tools grind on selection, and renderers anti-alias every rectangle's
edges separately.

**One `<path>` for everything.** Concatenate every module's outline into a single `d`
attribute and fill it once:

```xml
<path d="M32 32h8v8h-8z M48 32h8v8h-8z …" fill="#000000"/>
```

Each `M…h…v…z` run is one 8 × 8 module; thousands of modules become one element, one fill,
one node in every tool that opens the file. This is the structure UseQR emits — the whole
data region is a single path, with the three eyes drawn as separate paths (their ring
shape uses `fill-rule="evenodd"` to punch out the hole) so eye colour and shape can be
styled independently.

## The seam problem, and the three-part fix

The classic defect in QR SVGs is a grid of hairlines between modules — visible on screen
at some zoom levels, occasionally even in print. It is anti-aliasing: when adjacent
shapes share an edge at a fractional coordinate, the renderer blends each shape's edge
with the background separately, leaving a semi-transparent seam where they meet.

The fix is threefold, and all three parts appear in UseQR's output:

1. **Integer coordinates.** Modules are placed at
   `(column + quietZone) × moduleSize` with a default module size of 8 px and quiet zone
   of 4 modules — every square-module coordinate is a whole number, so edges land exactly
   on the pixel grid. (Curved styles round path coordinates to three decimals — precise
   enough that adjacent curves meet without gaps.)
2. **One merged path.** Sub-paths of a single filled path are composited together, not
   blended edge-by-edge against the background, so shared edges cannot produce seams.
3. **`shape-rendering="crispEdges"`** on the root, applied only for the square module
   style, telling renderers to prefer hard edges over anti-aliasing. Rounded, dot and
   organic [module styles](/docs/design/qr-code-module-shapes-compared) omit it — they
   *want* smooth curves, and their geometry does not tile edge-to-edge anyway.

## The parts around the path

A complete generated file is small and predictable: an optional `<defs>` block (gradients,
the logo's `clipPath`), a background `<rect>` (omitted entirely for
[transparent codes](/docs/design/transparent-background-qr-codes)), the merged data path,
three eye paths, then optional logo image and label text. The `viewBox` spans
`(modules + 2 × quietZone) × moduleSize`, so the [quiet zone](/glossary/quiet-zone) is
part of the document, not something the placing designer must remember to add.

One structural subtlety worth copying if you build your own: UseQR can emit an **SVG Tiny
1.2 profile** on request — no `clipPath`, no ARIA attributes, no `shape-rendering` —
because print RIPs, cutters and older Illustrator versions silently drop full-SVG features
they do not understand. Shipping markup a print shop's software ignores is how codes break
between proof and product; the [print rationale](/docs/print/why-you-should-print-qr-codes-from-svg)
covers that hand-off.

How the same matrix becomes canvas pixels instead is on
[rendering a QR code from a matrix](/docs/spec/rendering-a-qr-code-from-a-matrix); and
whatever the structure, [/validate](/validate) rasterising and decoding the result is the
test that matters.

## FAQ

### Why does my QR code SVG have thin white lines between squares?
Anti-aliasing seams: adjacent shapes at fractional coordinates get their shared edges blended separately against the background. Fix it with integer module coordinates, merging modules into one path, and shape-rendering set to crispEdges.

### Is one path better than many rects in a QR SVG?
Yes, for real use. One merged path means one element to style, faster parsing and rendering, no per-edge anti-aliasing between modules, and dramatically easier handling in design tools — a version 5 code is one node instead of roughly seven hundred.

### What is shape-rendering crispEdges for?
It is an SVG hint telling renderers to favour sharp, unblended edges over anti-aliasing. On a square-module QR code it eliminates hairline seams; on rounded or dot styles it is omitted because those shapes should stay smooth.

### Can I edit a QR code SVG in Illustrator or Figma?
You can recolour and scale it safely. Avoid reshaping or moving individual modules and never apply effects that shift geometry — and keep the quiet zone that the file's viewBox already includes. Verify the edited export still decodes before printing.

## Try it

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