Skip to content
UseQR
ESC

↑↓ MOVE↵ OPEN48 PLACES

Developers & agents

Generate a QR code in Go

With skip2/go-qrcode, one line writes a file: qrcode.WriteFile("https://example.com", qrcode.Medium, 512, "qr.png"). Encode returns PNG bytes for HTTP handlers. Alternatively fetch the keyless API with net/http and url.QueryEscape the payload. Verify styled codes with GET /api/v1/verify before shipping.

View as MarkdownPaste this page into any AI assistant — it is plain, portable Markdown.

The one-liner: skip2/go-qrcode

github.com/skip2/go-qrcode is the established Go library — pure Go, no cgo, no imaging dependency:

package main

import qrcode "github.com/skip2/go-qrcode"

func main() {
	err := qrcode.WriteFile("https://example.com", qrcode.Medium, 512, "qr.png")
	if err != nil {
		panic(err)
	}
}

qrcode.Low, Medium, High and Highest map to the four error-correction levels L, M, Q and H. The third argument is the image size in pixels; the library includes the 4-module quiet zone by default (there is a DisableBorder flag — leave it alone).

PNG bytes for an HTTP handler

Encode returns the bytes directly, which slots into net/http without touching disk:

func qrHandler(w http.ResponseWriter, r *http.Request) {
	data := r.URL.Query().Get("data")
	png, err := qrcode.Encode(data, qrcode.Medium, 512)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	w.Header().Set("Content-Type", "image/png")
	w.Header().Set("Cache-Control", "public, max-age=31536000, immutable")
	w.Write(png)
}

The immutable header is safe because the same input always produces identical output. For high-volume runs — one code per order or asset — a goroutine pool over WriteFile is plenty; patterns in bulk generation at scale.

The zero-dependency route: net/http

If you want styling (colours, module shapes) or typed payloads (WiFi, UPI, vCard) without writing renderer code, fetch the keyless API:

target := "https://example.com/sale?src=poster"
resp, err := http.Get(
	"https://useqr.app/api/v1/qr?data=" + url.QueryEscape(target) + "&size=1024",
)
if err != nil { /* handle */ }
defer resp.Body.Close()

f, _ := os.Create("qr.png")
defer f.Close()
io.Copy(f, resp.Body)

url.QueryEscape is the step people skip: a raw & in the payload becomes a second query parameter and truncates the encoded data without any error. No key, no auth — the same endpoint works from curl for quick comparison while debugging.

Note that go-qrcode outputs PNG only. For print work you want SVG, which the API returns with format=svg.

Verify before shipping

Decode-what-you-encode is one struct and one GET:

var report struct {
	Scannable bool     `json:"scannable"`
	Issues    []string `json:"issues"`
}
resp, _ := http.Get("https://useqr.app/api/v1/verify?data=" + url.QueryEscape(target))
json.NewDecoder(resp.Body).Decode(&report)
if !report.Scannable {
	log.Fatalf("qr failed verification: %v", report.Issues)
}

The endpoint renders the code, rasterises it and reads it back with a real decoder — the decode-verify loop without owning a decoder dependency.

FAQ

What is the standard Go library for QR codes?

github.com/skip2/go-qrcode — pure Go, no cgo. WriteFile writes a PNG in one call and Encode returns the bytes for HTTP handlers.

How do I set error correction in go-qrcode?

Pass qrcode.Low, Medium, High or Highest as the second argument. They correspond to the standard L, M, Q and H levels.

Can go-qrcode output SVG?

No, it produces PNG (and terminal strings). For SVG output, call the keyless API with format=svg or post-process the matrix yourself.

How do I encode a URL that contains query parameters?

Run it through url.QueryEscape before appending it to the API call. An unescaped ampersand silently truncates the payload at the server.

Try it — free, no signup

  • A free QR code API with no keyUseQR's REST API needs no signup, no API key and no SDK. GET /api/v1/qr?data=hello returns a PNG. The shortest form is /q/hello.png, which drops straight…
  • Generate a QR code with curlcurl -o qr.png \"https://useqr.app/q/hello.png\" is the whole thing. No key, no auth header, no SDK. Add query parameters for size, format and…
  • Bulk QR generation at scaleGenerating hundreds to millions of QR codes: the batch API and its limits, local generation with worker pools, determinism as a caching strategy, and manifests.
  • Why you should verify that a QR code decodesRendering a QR code proves nothing about whether it scans. Styling, colour, logos and print all consume error-correction budget invisibly. The only…