Developer — Web
The full AI SaaS boilerplate for the web. Streaming multi-model chat, a complete media studio with a job queue and gallery, authentication, a database, and storage — all wired and deploy-ready.
Requirements
- Node 22+
- Docker — a
docker-compose.ymlis included for local Postgres and Redis. Or bring your own. - An API key from at least one AI provider (optional to start — see below)
- A Clerk account for production auth (free tier is fine; optional in dev mode)
Quickstart
npm install
cp .env.example .env.local
docker compose up -d # local Postgres + Redis
npm run db:migrate # create the tables
npm run dev
Open http://localhost:3000.
Port conflicts
The included docker-compose.yml binds Postgres on 5432 and Redis on 6379. If you already run either locally, stop them first or change the ports in the compose file.
Configuration
AI providers (chat)
| Variable | Enables |
|---|---|
OPENAI_API_KEY | GPT models |
ANTHROPIC_API_KEY | Claude models |
GOOGLE_GENERATIVE_AI_API_KEY | Gemini models |
ZAI_API_KEY | GLM models |
DEEPSEEK_API_KEY | DeepSeek models |
DASHSCOPE_API_KEY | Qwen models |
These are your platform keys — the fallback used when a user has not supplied their own. Users can also add their own keys in Settings (BYOK); those are encrypted at rest with APP_ENCRYPTION_KEY and take precedence over the platform key.
Media
| Variable | Purpose |
|---|---|
FAL_KEY | fal.ai — image, video, audio |
REPLICATE_API_TOKEN | Replicate — the alternate provider |
MEDIA_PROVIDER | fal (default) or replicate |
Auth, data, storage
| Variable | Purpose |
|---|---|
CLERK_SECRET_KEY | Clerk auth. Leave blank for dev mode. |
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY | Clerk, client side |
DATABASE_URL | Postgres. Defaults to the docker-compose service. |
REDIS_URL | Redis. Defaults to the docker-compose service. |
BLOB_READ_WRITE_TOKEN | Vercel Blob storage. Falls back to local disk if unset. |
APP_ENCRYPTION_KEY | Encrypts user-supplied API keys at rest. Required in production. |
APP_URL | Public base URL. http://localhost:3000 in dev. |
CHAT_SYSTEM_PROMPT | Override the default system prompt |
APP_ENCRYPTION_KEY before you go live. Without it, user-supplied API keys cannot be encrypted at rest.Architecture
Pages
| Route | What it is |
|---|---|
/ | Landing page |
/chat | Streaming chat with a model picker and persistent history |
/studio | Media studio — image, video, audio generation |
/gallery | Every generation, browsable and downloadable |
/settings | BYOK key management |
/design | Design-token reference page |
API routes
| Route | Purpose |
|---|---|
POST /api/chat | Streaming chat completions |
POST /api/media | Enqueue a generation job |
GET /api/media/[id] | Poll job status |
GET /api/storage/[...key] | Serve stored media |
Database
Postgres via Drizzle ORM. Five tables:
| Table | Holds |
|---|---|
users | User records, keyed to the Clerk ID |
user_api_keys | BYOK keys, encrypted at rest |
conversations | Chat threads |
messages | Individual messages |
media_jobs | Generation jobs and their results |
Migrations live in lib/db/migrations/. Run npm run db:migrate to apply them, or npm run db:studio to browse the data.
The media pipeline
Generation is asynchronous. The client posts to /api/media, which writes a media_jobs row and returns an id; the client polls /api/media/[id] until the job completes. Providers (fal.ai, Replicate) sit behind a single contract in lib/media/providers.ts, so swapping providers means editing one module.
Scripts
| Command | What it does |
|---|---|
npm run dev | Dev server |
npm run build | Production build |
npm run db:migrate | Apply migrations |
npm run db:generate | Generate a migration from schema changes |
npm run db:studio | Browse the database |
npm run gate | Lint + typecheck + test |
Deploying
It is a standard Next.js app and deploys anywhere Next.js runs — Vercel, Fly, Railway, or your own host.
You will need, in production:
- A managed Postgres (Neon, Supabase, RDS…) →
DATABASE_URL - A managed Redis (Upstash, Redis Cloud…) →
REDIS_URL - Clerk production keys
- Blob storage →
BLOB_READ_WRITE_TOKEN(or the local-disk fallback, which will not survive on ephemeral hosts) APP_ENCRYPTION_KEY— do not skip thisAPP_URLset to your real domain
Run npm run db:migrate against the production database before first boot.
What this edition does not include
No billing. It is unmetered by design — no credits, no limits, no payment rails. Add your own, or upgrade to Business, which is this codebase plus the money layer.