Lesson 05
Deploy to Vercel + domain + protections
Your chatbot, in production, on your own domain, without the first bored botcoiner draining your API credits.
Basic deploy
npm install -g vercel
vercel
It will prompt you to log in, pick the project, and Vercel auto-detects Next.js.
Important: set the env var in the Vercel dashboard:
- Project → Settings → Environment Variables
ANTHROPIC_API_KEY= your key- Environment: Production + Preview + Development
- Encrypted ✅
Then: vercel --prod.
Connect your domain
In Vercel: Settings → Domains → Add.
If your domain is hosted elsewhere (Namecheap, OVH, Cloudflare):
- Apex domain: create an
Arecord pointing to76.76.21.21. www:CNAMEtocname.vercel-dns.com.
Vercel issues the SSL certificate automatically.
Non-negotiable protections
1. Rate limiting
Without this, the first bored kid who finds your chatbot can drain your API key.
npm install @upstash/ratelimit @upstash/redis
// app/api/chat/route.ts
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, "1 m"),
});
export async function POST(req: Request) {
const ip = req.headers.get("x-forwarded-for") ?? "anonymous";
const { success } = await ratelimit.limit(ip);
if (!success) {
return new Response("Too many requests", { status: 429 });
}
// ... rest of the route
}
Create a free DB on upstash.com, set UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN on Vercel.
2. Input validation
import { z } from "zod";
const Schema = z.object({
messages: z.array(z.object({
role: z.enum(["user", "assistant"]),
content: z.string().max(4000),
})).max(50),
});
export async function POST(req: Request) {
const parsed = Schema.safeParse(await req.json());
if (!parsed.success) {
return new Response("Invalid input", { status: 400 });
}
const { messages } = parsed.data;
// ...
}
3. Token cap per request
const totalChars = messages.reduce((acc, m) => acc + m.content.length, 0);
if (totalChars > 20000) {
return new Response("Conversation too long", { status: 400 });
}
4. Default to the cheap model
claude-haiku-4-5 costs a fraction of claude-opus-4-7 and for most casual chats is indistinguishable. Use Opus only when context exceeds ~50k tokens or reasoning is critical.
Monitoring
Vercel Analytics is free. For errors:
npm install @sentry/nextjs
Then configure sentry.client.config.ts with your DSN.
What you have shipped
- ✅ Chatbot with Claude API
- ✅ Conversational memory (with compression strategy)
- ✅ Tool use (weather; add whatever you want)
- ✅ Token streaming (fast UX)
- ✅ UI with Markdown and syntax highlighting
- ✅ Vercel deploy with custom domain
- ✅ Rate limiting and validation
Upgrades you can ship now
- Persistence: store conversations in Postgres (Neon, Supabase) so the user finds them on return.
- Auth: add NextAuth with Google or GitHub login.
- Multiple conversations: ChatGPT-style sidebar.
- Voice: Whisper for mic input and ElevenLabs for voice output.
Share the link with us. Great work. 🎉
Pro challenge
Pro challenge for this lesson
Same idea, no hints, graded by automated tests.
Hard Mode
Hard Mode
Extreme variant of the challenge. Time-bound with extra constraints.
Hard Mode
🏆 Boss Challenge
Build a multi-agent chatbot with persistent memory, tools, and voice — reviewed by a human mentor