Skip to content

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 A record pointing to 76.76.21.21.
  • www: CNAME to cname.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. 🎉


LEVEL 2

Pro challenge

Pro challenge for this lesson

Same idea, no hints, graded by automated tests.

Unlock Pro Mode · €29 One-time payment · lifetime access · no subscription
LEVEL 3

Hard Mode

Hard Mode

Extreme variant of the challenge. Time-bound with extra constraints.

Unlock Pro Mode · €29 One-time payment · lifetime access · no subscription
BOSS

Hard Mode

🏆 Boss Challenge

Build a multi-agent chatbot with persistent memory, tools, and voice — reviewed by a human mentor

Unlock Pro Mode · €29 One-time payment · lifetime access · no subscription