The AI Product Development Stack: What We Use and Why
The stack we reach for building AI products - Next.js, Supabase, Trigger.dev, OpenRouter, and more - with the reasoning behind each choice and when we deviate.
There's no single right stack for every AI product. But there's a default we reach for - a boring, well-supported, TypeScript-everywhere combination that handles the overwhelming majority of AI products well. This article walks through it, the reasoning behind each piece, and when we deviate.
The headline: stack varies by need, we pick the right tool not the trendy one. But for most AI products we build at AppSavvy, it lands here.
The default stack
- Next.js on Vercel - frontend + server actions + edge
- Supabase - Postgres, auth, storage, and pgvector for embeddings
- Drizzle ORM - TypeScript schema as the source of truth
- Trigger.dev - async, scheduled, and retryable work
- OpenRouter - model-agnostic AI routing
- Stripe - payments
- Resend or Postmark - transactional email
TypeScript end to end. No language boundary between frontend, backend, and AI orchestration. That single property removes a whole class of friction.
Why Next.js on Vercel
Next.js gives us server components (render on the server, send less JS), server actions (mutations without building an API layer by hand), and streaming (essential for responsive AI UX). Vercel gives us global edge deployment, preview environments per branch, and zero-config scaling.
For an AI product specifically, the streaming support matters most. AI responses take seconds; streaming them token by token is the difference between a product that feels alive and one that feels broken. Next.js + Vercel makes streaming straightforward.
The alternative we'd consider: if the product is API-first with no web UI, a lighter framework might fit. But most AI products have a UI, and Next.js is the strongest choice there.
Why Supabase
Supabase gives us four things in one place: Postgres (a real relational database), auth, storage, and pgvector (vector embeddings for retrieval).
That last point is the AI-specific win. Most AI products need both relational data and vector data. With Supabase, they live in the same Postgres instance with the same access-control model - row-level security applies to both. You don't run a separate vector database and reconcile two access models. (We do reach for a dedicated vector DB at very large scale; see the vector databases article for when.)
Row-level security is also how we ensure the AI never retrieves data a user shouldn't see - the access control is enforced at the database, not bolted onto the application.
Why Drizzle ORM
Drizzle keeps the database schema in TypeScript as the source of truth, generates SQL migrations, and gives type-safe queries. For an AI product, where the data model evolves fast in the early weeks, having the schema in version-controlled TypeScript - with migrations generated, not hand-written - keeps things sane.
Why Trigger.dev
AI work is slow and flaky. Model calls take seconds, sometimes fail, sometimes need retrying. Trigger.dev handles all the async, scheduled, and retryable work: background generation, batch processing, webhook handling, anything over a few seconds.
The key properties for AI: idempotency (a task won't double-charge or double-process), real retries with backoff (model API hiccups recover automatically), and observability (you can see every run). Rolling your own queue gives you none of these for free.
Why OpenRouter
We never hardcode one model provider. All AI traffic routes through OpenRouter (or a thin internal abstraction), so the specific model is configuration, not code. Swapping Claude for GPT for an open model is a config change.
In a market where the best model changes every few months, this is insurance, not a nice-to-have. It also lets us use the cheapest model that's good enough for each task - a token-economics win.
The pieces people forget
The stack above is the visible part. Two less-glamorous pieces are just as important for a real AI product:
Evaluation tooling
You need a way to test non-deterministic AI output. This is often custom - a harness that runs representative inputs against the current model/prompt and checks the outputs against criteria. It's not a product you buy off the shelf; it's part of the build.
Observability
You need to trace every AI call - input, model, context, output, cost, latency. Sometimes a dedicated LLM observability tool; sometimes structured logging into your own stack. Either way, it's not optional.
When we deviate from the default
The default stack handles most products. We deviate when:
- Strict data residency or self-hosting is required (e.g. regulated industries) - we run on the client's own cloud, sometimes with self-hosted open models
- The product is API-only with no web UI - a lighter backend framework may fit better than Next.js
- Extreme scale on vectors - a dedicated vector database alongside Postgres
- The client has an existing stack we should integrate with rather than replace - then we add AI to what exists
The point of having a default isn't to use it religiously. It's to start from a known-good baseline and deviate deliberately, for reasons, rather than assembling a random stack from scratch each time.
Why "boring" is the goal
Every piece of this stack is well-documented, widely adopted, and hire-able. When you bring on your next engineer, they already know Next.js and Postgres. When you hit a problem, the answer is on the internet. When you need to scale, the path is well-trodden.
The exciting part of an AI product is the AI capability and the user value. The stack should be boring so all your creative energy goes there, not into fighting your infrastructure.
What to do next
If you're building an AI product and want a stack that scales and stays maintainable, book a 30-minute discovery call.
Read next: AI-native architecture and Building AI products on Supabase.
Got a Bubble or Canvas app you’d like a second pair of eyes on?
30-minute discovery call. We’ll look at your app live and tell you honestly what we’d do next.
Or grab the Bubble migration playbook PDF.