# 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, 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
