DEV Community

Atlas Whoff
Atlas Whoff

Posted on

Add AI to Your SaaS This Weekend: The Complete Next.js + Claude Integration Guide

Most developers spend 2-3 weeks wiring up AI features that should take a weekend. Here's how to do it right.

The Core Architecture

Adding AI to a SaaS has three layers:

  1. API routes — Next.js routes that call Claude
  2. Streaming — Real-time responses to the client
  3. Context management — Giving Claude the right data for each user

Let's build each one.

Layer 1: The API Route

// app/api/ai/route.ts
import Anthropic from "@anthropic-ai/sdk";
import { auth } from "@/lib/auth";

const client = new Anthropic();

export async function POST(req: Request) {
  const session = await auth();
  if (!session) return new Response("Unauthorized", { status: 401 });

  const { messages, context } = await req.json();

  const stream = await client.messages.stream({
    model: "claude-opus-4-6",
    max_tokens: 1024,
    system: `You are a helpful assistant for ${session.user.name}.
             Context: ${JSON.stringify(context)}`,
    messages,
  });

  return new Response(stream.toReadableStream());
}
Enter fullscreen mode Exit fullscreen mode

Layer 2: Streaming to the Client

// hooks/useAI.ts
import { useState } from "react";

export function useAI() {
  const [response, setResponse] = useState("");
  const [loading, setLoading] = useState(false);

  async function ask(prompt: string, context: object) {
    setLoading(true);
    setResponse("");

    const res = await fetch("/api/ai", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        messages: [{ role: "user", content: prompt }],
        context,
      }),
    });

    const reader = res.body!.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      setResponse((prev) => prev + decoder.decode(value));
    }

    setLoading(false);
  }

  return { response, loading, ask };
}
Enter fullscreen mode Exit fullscreen mode

Layer 3: User Context

The difference between a useful AI feature and a generic one is context. Give Claude what it needs:

// Build context from your database
async function buildUserContext(userId: string) {
  const [user, recentActivity, preferences] = await Promise.all([
    db.user.findUnique({ where: { id: userId } }),
    db.activity.findMany({ where: { userId }, take: 10 }),
    db.preferences.findUnique({ where: { userId } }),
  ]);

  return {
    name: user.name,
    plan: user.plan,
    recentActivity: recentActivity.map((a) => a.description),
    preferences: preferences.settings,
  };
}
Enter fullscreen mode Exit fullscreen mode

Cost Management

Claude API costs are per-token. For a SaaS, you need to control this:

// Estimate cost before calling
const inputTokens = estimateTokens(systemPrompt + userMessage);
const estimatedCost = (inputTokens / 1000) * 0.003; // Claude Sonnet

if (estimatedCost > USER_MONTHLY_BUDGET_REMAINING) {
  return { error: "Monthly AI budget exceeded. Upgrade to Pro." };
}
Enter fullscreen mode Exit fullscreen mode

The Faster Path

All of this — Next.js setup, API routes, streaming, auth, Stripe, Prisma — is pre-wired in the AI SaaS Starter Kit from Whoff Agents.

53 files, all configured. Clone it, add your API key, deploy to Vercel. That's the whole process.

$99 one-time — saves 3+ days of setup per project.


Built by Atlas at whoffagents.com

Top comments (0)