How I Built a Production-Ready AI SaaS Boilerplate with Next.js 16 — Full Stack Breakdown A developer built ShipAI, a production-ready Next.js 16 boilerplate for AI SaaS applications that pre-configures authentication via NextAuth.js, Stripe subscriptions and webhooks, Prisma with PostgreSQL, and the Vercel AI SDK v4 with OpenAI and Anthropic providers. The project spans 48 files and 16 routes with zero TypeScript errors, and the developer documented migration gotchas including Vercel AI SDK v4's replacement of useChat's input, handleInputChange and append with sendMessage and a DefaultChatTransport pattern, and the need for connection() plus instant = false under Cache Components. The developer also advises using prisma.subscription.upsert() because checkout.session.completed can fire before a subscription record exists, and recommends Prisma v5 over v8 for its familiar CLI workflow. Every time I started a new AI SaaS project, I spent the first 2-3 weeks on the same things: authentication, Stripe integration, database setup, AI provider plumbing. Over and over. So I built ShipAI — a production-ready Next.js 16 boilerplate that has all of this pre-configured and ready to customize. | Layer | Tech | |---|---| | Framework | Next.js 16 App Router, TypeScript, Turbopack | | Auth | NextAuth.js Google, GitHub, email/password | | Payments | Stripe subscriptions, webhooks, customer portal | | Database | Prisma + PostgreSQL | | AI | Vercel AI SDK v4 OpenAI + Anthropic | | UI | Tailwind CSS + 15 shadcn/ui components | | | Resend | | Deploy | Vercel one-click | 48 files. 16 routes. Zero TypeScript errors. If you're upgrading from v3, heads up: useChat no longer exposes input , handleInputChange , or append . The new API uses sendMessage and a transport pattern DefaultChatTransport . I spent time figuring this out so you don't have to. export const dynamic = "force-dynamic" no longer works with Cache Components enabled. Use connection from next/server plus export const instant = false for dynamic server pages. checkout.session.completed can fire before the subscription record exists in your database. Always use prisma.subscription.upsert instead of separate create/update calls. Prisma v8 has a completely different CLI and is more of a platform play. For a developer-friendly boilerplate, Prisma v5 with the familiar npx prisma generate workflow is the right choice. If you're building AI SaaS products and want to skip the boilerplate phase: Happy to answer any questions about the architecture or technical decisions in the comments