A web app for designing customizable QR codes: pick colors, dot styles, size, and error correction, preview live, export PNG, and optionally save designs to a personal dashboard. Saved codes are stored with automatic cleanup after 30 days (via a scheduled job on Vercel).
This repository is intended for anyone who wants to run the app locally or deploy their own instance.
- Live visual editor with instant preview
- High-quality PNG export
- Optional accounts: sign up, sign in, and manage a history of saved QR codes
- Automatic purge of old saved codes (cron; configurable secret)
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router) on React 19 |
| Language | TypeScript |
| Styling | Tailwind CSS v4 (PostCSS pipeline) |
| Database | PostgreSQL via Neon serverless driver |
| ORM & migrations | Drizzle ORM + Drizzle Kit |
| Auth | Better Auth with email/password, Drizzle adapter, Next.js cookie helpers |
| File storage | Vercel Blob for persisted QR images |
| QR rendering | qr-code-styling for customizable QR appearance |
| IDs | nanoid for short unique identifiers |
| Linting | ESLint with eslint-config-next |
Why these pieces: Next.js provides server components, API routes, and a straightforward deploy story. Neon + Drizzle keep the data layer small and migration-friendly. Better Auth handles sessions and credentials stored in your Postgres schema. Vercel Blob stores generated images when users save codes to the dashboard.
Runtime dependencies
next,react,react-dom— UI and routingdrizzle-orm— type-safe SQL / schema@neondatabase/serverless— connect to Neon (or any Postgres URL you provide)better-auth— authentication@vercel/blob— upload and read QR images in Blob storageqr-code-styling— QR generation and styling in the browsernanoid— unique IDs for resources
Development dependencies
drizzle-kit—db:generate,db:migrate,db:push,db:studio@better-auth/cli— optional Better Auth CLI taskstailwindcss,@tailwindcss/postcss— stylingtypescript,@types/*— typingeslint,eslint-config-next— lintingdotenv— loaded by Drizzle Kit for local env
- Node.js 20.x or newer (recommended; aligns with Next.js 16 and the toolchain)
- npm (this repo includes
package-lock.json; you can also usepnpmoryarnif you prefer and generate your own lockfile) - A PostgreSQL database (e.g. Neon free tier)
- A Vercel Blob store with a read-write token (for saving QR images to the dashboard)
- For production on Vercel: set environment variables in the project; optional
CRON_SECRETfor the purge endpoint used byvercel.json
git clone <your-fork-or-repo-url>
cd QRCodeCreator_Opennpm installCopy the example file and fill in values:
cp .env.example .env.local| Variable | Purpose |
|---|---|
DATABASE_URL |
PostgreSQL connection string (Neon pooled URL works) |
BETTER_AUTH_SECRET |
Long random secret; e.g. openssl rand -base64 32 |
BETTER_AUTH_URL |
App base URL with no trailing slash, e.g. http://localhost:3000 |
BLOB_READ_WRITE_TOKEN |
Vercel Blob read-write token |
NEXT_PUBLIC_APP_URL |
Optional; public origin if it differs from BETTER_AUTH_URL |
CRON_SECRET |
Optional locally; on Vercel, protects /api/cron/purge when set |
On Vercel, BETTER_AUTH_URL can be omitted if you rely on VERCEL_URL for server-side URL resolution (see src/lib/url.ts).
Apply the schema to your database (choose one):
- Push schema (good for local dev):
npm run db:push - Or run migrations:
npm run db:migrate(uses files underdrizzle/)
Optional: open Drizzle Studio with npm run db:studio.
npm run devOpen http://localhost:3000.
npm run build
npm run start| Command | Description |
|---|---|
npm run dev |
Next.js dev server with hot reload |
npm run build |
Production build |
npm run start |
Run production server (after build) |
npm run lint |
ESLint |
npm run db:generate |
Generate SQL migrations from schema changes |
npm run db:migrate |
Apply migrations |
npm run db:push |
Push schema directly to the database |
npm run db:studio |
Drizzle Studio UI |
The app is a standard Next.js deployment. Vercel is a natural fit: connect the repo, set the same environment variables as in .env.example, and ensure DATABASE_URL, BETTER_AUTH_SECRET, and BLOB_READ_WRITE_TOKEN are set in production.
vercel.json defines a daily cron that calls GET /api/cron/purge. Set CRON_SECRET in your Vercel project environment; Vercel’s cron invocations include Authorization: Bearer <CRON_SECRET>, which matches what src/app/api/cron/purge/route.ts checks. Without CRON_SECRET, the purge endpoint returns 503.
src/app/— App Router pages and API routes (api/auth,api/qr,api/cron, etc.)src/components/— UI components (editor, gallery, header)src/db/— Drizzle client and schemadrizzle/— Generated SQL migrations