A high-performance QR code generation system built with Rust and SolidJS. Supports URL, text, vCard, WiFi, and email QR codes with customizable colors, logo embedding, and bulk generation.
Ships as a REST API, CLI tool, and web frontend — all from a single codebase, deployable as a single Docker container.
- Features
- Tech Stack
- Project Structure
- Getting Started
- Usage
- Configuration
- API Reference
- Postman Collection
- CLI Reference
- Architecture
- Roadmap
- License
- Multiple QR content types — URL, plain text, vCard contacts, WiFi credentials, email
- Multiple output formats — PNG, SVG, JPEG
- Custom styling — foreground/background colors, configurable size (128–2048px)
- Logo embedding — overlay a logo image in the center of the QR code
- Error correction levels — Low, Medium, Quartile, High
- Quiet zone control — configurable margin (0–10 modules)
- Bulk generation — submit a list of items, receive a ZIP archive
- REST API with JSON request/response and binary image download
- Interactive API docs — auto-generated Swagger UI via OpenAPI
- CLI tool — generate QR codes from the command line
- Web frontend — dark-themed, responsive SolidJS single-page app
- API key authentication — configurable via environment variables
- Per-IP rate limiting — in-memory, configurable requests/minute
- Graceful shutdown — handles SIGTERM properly for container orchestration
- Single Docker container — API + frontend + CLI in one image (~50–80MB)
| Layer | Technology |
|---|---|
| Core QR Library | Rust — qrcode, image, zip crates |
| REST API | Rust — Axum, Tokio, Tower, tower-http |
| API Documentation | utoipa + Swagger UI (auto-generated OpenAPI) |
| CLI | Rust — Clap v4 |
| Frontend | SolidJS + TypeScript |
| Frontend Tooling | Bun + Vite |
| Deployment | Docker (multi-stage build) |
qr-code-gen/
├── Cargo.toml # Workspace root
├── Cargo.lock # Locked dependencies (committed for reproducible builds)
├── Dockerfile # Multi-stage build (Bun + Rust → Debian slim)
├── docker-compose.yml # Single-command production deployment
├── .env.example # Environment variable reference
├── .gitignore
├── .dockerignore
│
├── postman/
│ └── QR_Code_Generator_API.postman_collection.json # Importable Postman collection
│
├── crates/
│ ├── qr-core/ # Core QR generation library
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── lib.rs # Public API and re-exports
│ │ ├── generator.rs # QR generation engine (PNG/SVG/JPEG + logo overlay)
│ │ ├── types.rs # Content types (URL, vCard, WiFi, Email)
│ │ ├── style.rs # Styling: colors, size, quiet zone, logo config
│ │ ├── bulk.rs # Bulk generation → ZIP archive
│ │ └── error.rs # Error types
│ │
│ ├── qr-api/ # Axum REST API server
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── main.rs # Server setup, routing, Swagger UI, static file serving
│ │ ├── config.rs # Environment-based configuration
│ │ ├── state.rs # Shared app state + in-memory rate limiter
│ │ ├── errors.rs # Structured API error responses
│ │ ├── models.rs # Request/response types with OpenAPI schemas
│ │ ├── routes/
│ │ │ ├── mod.rs
│ │ │ ├── generate.rs # POST /api/generate, POST /api/generate/base64
│ │ │ ├── bulk.rs # POST /api/bulk
│ │ │ └── health.rs # GET /health
│ │ └── middleware/
│ │ ├── mod.rs
│ │ ├── auth.rs # API key authentication
│ │ └── rate_limit.rs # Per-IP rate limiting
│ │
│ └── qr-cli/ # Command-line tool
│ ├── Cargo.toml
│ └── src/
│ └── main.rs # Clap-based CLI with url/text/vcard/wifi/email/bulk subcommands
│
├── frontend/ # SolidJS single-page application
│ ├── package.json
│ ├── bun.lock
│ ├── tsconfig.json
│ ├── vite.config.ts # Vite config with API proxy for dev
│ ├── index.html
│ └── src/
│ ├── index.tsx # App entry point
│ ├── App.tsx # Main app layout (Single/Bulk tabs)
│ ├── api/
│ │ └── client.ts # Typed API client functions
│ ├── components/
│ │ ├── TypeSelector.tsx # URL / Text / vCard / WiFi / Email tabs
│ │ ├── QrForm.tsx # Content input forms for each type
│ │ ├── StyleOptions.tsx # Colors, size, error correction, logo upload
│ │ ├── QrPreview.tsx # Live preview + download buttons (PNG/SVG/JPEG)
│ │ └── BulkUpload.tsx # JSON/URL list input → ZIP download
│ └── styles/
│ └── global.css # Dark theme, responsive layout
│
└── tests/
└── integration/ # Integration tests (future)
For local development:
- Rust (1.75+ recommended)
- Bun (1.0+) — for frontend builds
- (Optional) Docker — for containerized deployment
For Docker-only deployment:
- Docker and Docker Compose — that's it, nothing else needed
1. Clone the repository:
git clone <your-repo-url>
cd qr-code-gen2. Build the frontend:
cd frontend
bun install
bun run build
cd ..3. Run the API server:
cargo run -p qr-apiThe server starts at http://localhost:3000 with:
- Web frontend at
/ - API endpoints at
/api/* - Swagger docs at
/api/docs
No environment setup required for local development — all config has sensible defaults.
For frontend hot-reload during development (optional), run two terminals:
# Terminal 1: Rust API server
cargo run -p qr-api
# Terminal 2: Vite dev server with hot module replacement
cd frontend && bun run devThen open http://localhost:5173 — Vite proxies API requests to the Rust server automatically.
Note:
cargo runcompiles in debug mode (fast compilation, slower runtime). This is fine for development. The Docker build uses--releasefor optimized production binaries.
Single command — builds and runs everything:
docker compose up --buildThis:
- Builds the SolidJS frontend with Bun
- Compiles optimized Rust binaries with
cargo build --release - Creates a slim runtime image (~50–80MB)
- Starts the server on port 3000
Open http://localhost:3000 — frontend, API, and Swagger docs all served from one container.
To run in the background:
docker compose up --build -dTo stop:
docker compose downOpen http://localhost:3000 in your browser. The frontend provides:
-
Single mode — Generate one QR code at a time
- Select content type (URL, Text, vCard, WiFi, Email)
- Fill in the form fields
- Customize colors, size, error correction level, and quiet zone
- Upload a logo image for center overlay
- Click "Generate QR Code" to preview
- Download as PNG, SVG, or JPEG
-
Bulk mode — Generate multiple QR codes at once
- Paste a list of URLs (one per line) or a JSON array of items
- Upload a JSON file
- Download all generated QR codes as a ZIP archive
Generate a QR code (binary image):
curl -X POST http://localhost:3000/api/generate \
-H "Content-Type: application/json" \
-d '{
"content": {"type": "Url", "data": "https://example.com"},
"format": "Png",
"error_correction": "Medium",
"style": {
"size": 512,
"foreground_color": "#000000",
"background_color": "#FFFFFF",
"quiet_zone": 2,
"logo_size_percent": 20
}
}' \
--output qrcode.pngGenerate a QR code (base64 JSON):
curl -X POST http://localhost:3000/api/generate/base64 \
-H "Content-Type: application/json" \
-d '{
"content": {"type": "Url", "data": "https://example.com"},
"format": "Png",
"error_correction": "Medium",
"style": {"size": 512}
}'Response:
{
"image": "iVBORw0KGgo...",
"data_uri": "data:image/png;base64,iVBORw0KGgo...",
"content_type": "image/png",
"size_bytes": 2450
}Generate WiFi QR code:
curl -X POST http://localhost:3000/api/generate \
-H "Content-Type: application/json" \
-d '{
"content": {
"type": "WiFi",
"data": {
"ssid": "MyNetwork",
"encryption": "WPA",
"password": "secret123",
"hidden": false
}
},
"format": "Png",
"error_correction": "High",
"style": {"size": 512}
}' \
--output wifi-qr.pngBulk generation (ZIP):
curl -X POST http://localhost:3000/api/bulk \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"name": "example-1",
"content": {"type": "Url", "data": "https://example.com"},
"format": "Png",
"error_correction": "Medium",
"style": {"size": 512}
},
{
"name": "github",
"content": {"type": "Url", "data": "https://github.com"},
"format": "Svg",
"error_correction": "High",
"style": {"size": 256}
}
]
}' \
--output qrcodes.zip# Generate URL QR code
cargo run -p qr-cli -- url "https://example.com" -o qrcode.png
# Generate with custom colors and size
cargo run -p qr-cli -- url "https://github.com" \
--fg-color "#1e40af" --bg-color "#eff6ff" \
-s 1024 -o blue-qr.png
# Generate SVG format
cargo run -p qr-cli -- url "https://example.com" -f svg -o qrcode.svg
# Generate vCard contact QR
cargo run -p qr-cli -- vcard \
--first-name "John" --last-name "Doe" \
--phone "+1234567890" --email "john@example.com" \
--org "Acme Corp" -o contact.png
# Generate WiFi QR code
cargo run -p qr-cli -- wifi \
--ssid "MyNetwork" --password "secret123" \
--encryption wpa -o wifi.png
# Generate email QR code
cargo run -p qr-cli -- email "hello@example.com" \
--subject "Hello" --body "Nice to meet you" \
-o email.png
# Generate with logo overlay
cargo run -p qr-cli -- url "https://example.com" \
--logo ./logo.png --logo-size 25 --ec-level high \
-o branded-qr.png
# Bulk generation from JSON file
cargo run -p qr-cli -- bulk items.json --output-dir ./output/
# Bulk generation as ZIP
cargo run -p qr-cli -- bulk items.json --zip --output-dir ./output/All configuration is via environment variables. No .env file is required for local development — all values have sensible defaults.
| Variable | Default | Description |
|---|---|---|
HOST |
0.0.0.0 |
Server bind address |
PORT |
3000 |
Server port |
RUST_LOG |
info |
Log level (trace, debug, info, warn, error) |
API_KEYS |
(empty) | Comma-separated API keys. Auth is disabled when empty. |
RATE_LIMIT_PER_MINUTE |
60 |
Max requests per minute per IP |
MAX_BODY_SIZE |
10485760 |
Maximum request body size in bytes (10MB) |
CORS_ORIGINS |
* |
Allowed CORS origins (comma-separated, or * for all) |
FRONTEND_DIR |
./frontend/dist |
Path to built frontend static files |
No configuration needed. Just run:
cargo run -p qr-apiCreate a .env file or set environment variables:
cp .env.example .envRecommended production settings:
# Enable authentication
API_KEYS=your-secure-key-1,your-secure-key-2
# Adjust rate limit
RATE_LIMIT_PER_MINUTE=120
# Structured logging
RUST_LOG=infoWhen API_KEYS is set, all /api/* endpoints require authentication via:
- Header:
Authorization: Bearer <your-api-key> - Query param:
?api_key=<your-api-key>
The following endpoints are always public (no auth required):
GET /healthGET /api/docs(Swagger UI)GET /(frontend)
| Method | Endpoint | Description | Auth |
|---|---|---|---|
GET |
/health |
Health check ({"status":"ok","version":"0.1.0"}) |
No |
POST |
/api/generate |
Generate QR code → binary image download | Yes* |
POST |
/api/generate/base64 |
Generate QR code → JSON with base64 data URI | Yes* |
POST |
/api/bulk |
Bulk generate → ZIP archive download | Yes* |
GET |
/api/docs |
Swagger UI (interactive API documentation) | No |
GET |
/api-docs/openapi.json |
Raw OpenAPI specification | No |
GET |
/ |
Web frontend (SolidJS SPA) | No |
*Auth required only when API_KEYS is configured.
// URL
{"type": "Url", "data": "https://example.com"}
// Plain text
{"type": "Text", "data": "Hello, World!"}
// vCard contact
{"type": "VCard", "data": {
"first_name": "John",
"last_name": "Doe",
"organization": "Acme Corp",
"title": "Engineer",
"phone": "+1234567890",
"email": "john@example.com",
"website": "https://example.com",
"address": "123 Main St"
}}
// WiFi network
{"type": "WiFi", "data": {
"ssid": "NetworkName",
"encryption": "WPA",
"password": "secret123",
"hidden": false
}}
// Email
{"type": "Email", "data": {
"to": "hello@example.com",
"subject": "Hello",
"body": "Message body"
}}| Field | Type | Default | Description |
|---|---|---|---|
size |
integer | 512 |
Output image size in pixels (64–4096) |
foreground_color |
string | "#000000" |
QR module color (hex) |
background_color |
string | "#FFFFFF" |
Background color (hex) |
quiet_zone |
integer | 2 |
Margin in modules (0–10) |
logo_base64 |
string | null |
Base64-encoded logo image |
logo_size_percent |
integer | 20 |
Logo size as % of QR code (1–40) |
| Value | MIME Type | Extension |
|---|---|---|
Png |
image/png |
.png |
Svg |
image/svg+xml |
.svg |
Jpeg |
image/jpeg |
.jpg |
| Value | Recovery | Best For |
|---|---|---|
Low |
~7% | Maximum data density |
Medium |
~15% | General use (default) |
Quartile |
~25% | Moderate error tolerance |
High |
~30% | Logo embedding, printed QR codes |
A ready-to-use Postman collection is included at postman/QR_Code_Generator_API.postman_collection.json.
- Open Postman
- Click Import (top-left)
- Select the file
postman/QR_Code_Generator_API.postman_collection.json - The collection will appear in your sidebar
The collection includes 17 pre-built requests organized into folders:
| Folder | Requests | Description |
|---|---|---|
| Health | 1 | Health check endpoint |
| Generate — Single QR Code | 10 | URL, Text, vCard, WiFi, Email, custom colors, SVG format, minimal request, high EC |
| Bulk Generation | 2 | Multiple URLs, mixed content types |
| Error Cases | 4 | Invalid URL, empty content, invalid email, empty bulk request |
After importing, set these variables in the collection settings:
| Variable | Default | Description |
|---|---|---|
base_url |
http://localhost:3000 |
Server URL. Change for staging/production. |
api_key |
(empty) | Your API key. Leave empty if auth is disabled on the server. |
Every request inherits Bearer token auth from the collection level, so setting api_key once applies to all requests automatically.
qr-cli <COMMAND>
Commands:
url Generate a QR code from a URL
text Generate a QR code from plain text
vcard Generate a QR code from vCard contact info
wifi Generate a QR code for WiFi network
email Generate a QR code for an email
bulk Generate multiple QR codes from a JSON file
help Print this message or the help of the given subcommand(s)
| Option | Short | Default | Description |
|---|---|---|---|
--output |
-o |
qrcode.png |
Output file path |
--format |
-f |
png |
Output format: png, svg, jpeg |
--size |
-s |
512 |
Image size in pixels |
--fg-color |
#000000 |
Foreground color (hex) | |
--bg-color |
#FFFFFF |
Background color (hex) | |
--ec-level |
medium |
Error correction: low, medium, quartile, high |
|
--quiet-zone |
2 |
Quiet zone margin (modules) | |
--logo |
Path to logo image file | ||
--logo-size |
20 |
Logo size as percentage (1–40) |
┌─────────────────────────────────────────────────────┐
│ Docker Container │
│ │
│ ┌────────────┐ ┌─────────────────────────────┐ │
│ │ SolidJS │ │ Rust (Axum) API │ │
│ │ Frontend ├───►│ │ │
│ │ (static) │ │ ┌───────────────────────┐ │ │
│ └────────────┘ │ │ qr-core lib │ │ │
│ │ │ (stateless engine) │ │ │
│ │ └───────────────────────┘ │ │
│ │ │ │
│ │ Middleware: │ │
│ │ ├── CORS │ │
│ │ ├── API key auth │ │
│ │ ├── Rate limiting (in-mem) │ │
│ │ └── Request tracing │ │
│ │ │ │
│ │ Config: env vars │ │
│ └─────────────────────────────┘ │
│ │
│ [ Fully stateless — no database ] │
└─────────────────────────────────────────────────────┘
The project uses a Cargo workspace with three crates:
qr-core— Pure library crate. Contains all QR generation logic, content type encoding, styling, logo overlay, and bulk ZIP creation. Zero framework dependencies. Can be used independently.qr-api— Binary crate. Axum web server that exposesqr-coreas a REST API. Handles authentication, rate limiting, CORS, request validation, and serves the frontend.qr-cli— Binary crate. Clap-based command-line tool that callsqr-coredirectly. No network dependency.
The Docker build is a 3-stage process:
- Frontend builder (Bun) — installs dependencies and builds the SolidJS app
- Rust builder — compiles both binaries in release mode with dependency caching
- Runtime (Debian slim) — copies only the binaries and static files (~50–80MB final image)
Future additions that can be built on top of this foundation:
- Analytics / scan tracking — SQLite-backed redirect endpoint to count QR scans
- Short URL integration — Shorten URLs before encoding to reduce QR complexity
- Template styles — Rounded modules, dot patterns, gradient fills
- QR code reader — Decode uploaded QR code images
- Batch CSV import — Upload a CSV file for bulk generation in the web UI
- Download history — Track recently generated QR codes (browser local storage)
- API usage dashboard — Per-key usage metrics and quota tracking
- Integration tests — Comprehensive test suite for core library and API
MIT