Low Level Design: QR Code Generator Service

What Is a QR Code Generator Service?

A QR Code Generator Service accepts arbitrary data (URLs, vCards, plain text) and returns a scannable QR code image. Internally it encodes the input into a binary matrix following the ISO/IEC 18004 standard, then renders that matrix as a PNG, SVG, or WebP. At product scale the service must handle burst traffic from marketing campaigns, support custom branding (logo overlays, color palettes), and cache results to avoid redundant computation.

Data Model

Generated QR codes are deterministic for a given set of parameters, so caching by a content hash is the primary optimization.

CREATE TABLE qr_code (
    id            BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    content_hash  CHAR(64)     NOT NULL UNIQUE,  -- SHA-256 of (data + options)
    raw_data      TEXT         NOT NULL,
    format        ENUM('png','svg','webp') DEFAULT 'png',
    error_level   ENUM('L','M','Q','H')  DEFAULT 'M',
    size_px       SMALLINT     DEFAULT 256,
    storage_key   VARCHAR(512),                  -- object storage path
    created_at    DATETIME     DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_hash (content_hash)
);

CREATE TABLE qr_request_log (
    id            BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    qr_code_id    BIGINT UNSIGNED NOT NULL,
    user_id       BIGINT UNSIGNED,
    requested_at  DATETIME DEFAULT CURRENT_TIMESTAMP,
    ip_address    VARCHAR(45),
    FOREIGN KEY (qr_code_id) REFERENCES qr_code(id)
);

Core Algorithm: QR Matrix Generation

QR code generation follows a well-defined pipeline:

  1. Data analysis: Detect the most compact encoding mode for the input: Numeric, Alphanumeric, Byte, or Kanji.
  2. Error correction: Apply Reed-Solomon coding at the chosen level (L=7%, M=15%, Q=25%, H=30% recovery capacity). Higher levels produce larger matrices.
  3. Version selection: Choose the smallest QR version (1-40) whose data capacity fits the encoded payload. Version 1 is 21×21 modules; each version adds 4 modules per side.
  4. Module placement: Fill the matrix with finder patterns, timing patterns, alignment patterns, format info, and finally the data & error-correction codewords.
  5. Masking: Apply each of 8 mask patterns, score each result against ISO penalty rules, and select the mask with the lowest score to balance dark/light module density.
  6. Render: Convert the boolean matrix to the target image format. For PNG, use a quiet zone of 4 modules. For SVG, emit <rect> elements grouped per row for compact output.
function generate(data, error_level, format):
    mode    = detect_encoding_mode(data)
    version = select_version(data, mode, error_level)
    bits    = encode_data(data, mode, version)
    ec_bits = reed_solomon(bits, error_level, version)
    matrix  = build_matrix(version, bits + ec_bits)
    matrix  = apply_best_mask(matrix)
    return render(matrix, format)

Caching Strategy

QR generation is CPU-bound. Cache aggressively at two layers:

  • Redis: Store the object-storage key keyed by content_hash. TTL 24 hours for ephemeral; no TTL for permanent branded codes.
  • Object Storage (S3/GCS): Store the rendered image. Return a pre-signed URL or a CDN URL. Avoid regenerating the same image on every request.

On a cache hit the service returns the CDN URL in under 5 ms without touching the generator worker pool.

Failure Handling

  • Invalid input: Validate data length against the maximum capacity for the requested version and error level before invoking the generator. Return a 400 with a descriptive message.
  • Generator worker crash: Run workers in a process pool behind a job queue (e.g., Celery, BullMQ). Failed jobs are retried up to 3 times with backoff before a dead-letter queue captures them.
  • Object storage unavailable: Fall back to returning the raw base64-encoded image inline in the API response so the caller is not completely blocked.
  • Logo overlay failure: Treat logo compositing as an optional step. If it fails, return the plain QR code rather than erroring the entire request.

Scalability Considerations

  • Worker autoscaling: Monitor the job queue depth. Scale generator workers up when depth exceeds a threshold, scale down during off-peak hours.
  • Pre-warming: For known campaign URLs, pre-generate QR codes before launch to eliminate cold-start latency spikes.
  • Format negotiation: Serve SVG by default (vector, small) and PNG only when the client explicitly requests a raster format. This reduces storage and CDN egress costs.
  • Rate limiting: Enforce per-API-key generation limits. Regenerating the same content hash counts as a cache hit and does not consume quota.

Summary

A QR Code Generator Service is compute-heavy on generation and read-heavy on retrieval. The winning architecture pairs a small pool of generator workers with aggressive two-layer caching: Redis for metadata, object storage plus CDN for rendered images. Content-hash deduplication eliminates redundant work, and a job queue absorbs traffic spikes without dropping requests.

{
“@context”: “https://schema.org”,
“@type”: “FAQPage”,
“mainEntity”: [
{
“@type”: “Question”,
“name”: “What is the high-level architecture of a QR code generator service?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “A QR code generator service consists of an API layer that accepts input data and rendering parameters, a QR encoding library (e.g., based on the ISO 18004 standard) that converts data into the QR matrix, an image rendering layer that outputs PNG, SVG, or PDF, an object store (such as S3) for caching generated images, and a CDN for low-latency delivery to end users.”
}
},
{
“@type”: “Question”,
“name”: “How do you handle QR code generation at scale without regenerating the same image repeatedly?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Hash the combination of input data and rendering options (size, error correction level, colors) to produce a cache key. Check the object store or a distributed cache for that key before generating. On a cache miss, generate and store the result, then return it. This turns most requests into cheap cache lookups and drastically reduces CPU usage.”
}
},
{
“@type”: “Question”,
“name”: “What error correction levels exist in QR codes and when should each be used?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “QR codes support four error correction levels: L (7% recovery), M (15%), Q (25%), and H (30%). Use L or M when the QR code will be displayed cleanly on a screen. Use Q or H when the code will be printed on physical materials that may get dirty or partially damaged, or when a logo will be overlaid on the center of the code.”
}
},
{
“@type”: “Question”,
“name”: “How would you design a dynamic QR code system where the destination can be changed after printing?”,
“acceptedAnswer”: {
“@type”: “Answer”,
“text”: “Encode a short redirect URL (from a URL shortener service) into the QR code rather than the final destination. Changing the redirect mapping in the URL shortener’s database instantly updates where the QR code resolves, without reprinting. This decouples the static QR image from the mutable destination, and you can layer analytics on top of the redirect service.”
}
}
]
}

See also: Netflix Interview Guide 2026: Streaming Architecture, Recommendation Systems, and Engineering Excellence

See also: Meta Interview Guide 2026: Facebook, Instagram, WhatsApp Engineering

See also: Snap Interview Guide

Scroll to Top