Best Convex Boilerplates for SaaS in 2026
Convex is not a traditional database. It's a backend-as-a-service platform where you write TypeScript functions that run server-side, and your React components subscribe to those functions' return values in real-time — no polling, no WebSocket code, no cache invalidation logic. When the data changes on the server, all subscribed clients update automatically.
For SaaS products, this changes how you think about building features. A dashboard that shows "users online right now" isn't a complex WebSocket engineering problem — it's a Convex query that multiple clients subscribe to. A collaborative document editor isn't a complex synchronization challenge — it's Convex mutations with automatic conflict resolution.
In 2026, a growing set of SaaS boilerplates have adopted Convex as their primary backend, replacing the Supabase/Prisma/PostgreSQL stack. Here's what's available.
Why Convex for SaaS
// Traditional stack: database query + API route + cache
// lib/api/users.ts
export async function getUser(userId: string) {
return await prisma.user.findUnique({ where: { id: userId } });
}
// app/api/users/[id]/route.ts — API route to expose it
// hooks/useUser.ts — React Query fetch + cache + stale invalidation
// 3 files, cache management, manual refetch on update
// Convex approach: one function, live updates
// convex/users.ts
export const getUser = query({
args: { userId: v.id('users') },
handler: async (ctx, { userId }) => {
return await ctx.db.get(userId);
},
});
// React component
function UserProfile({ userId }) {
const user = useQuery(api.users.getUser, { userId });
// Automatically re-renders when user data changes server-side
// No polling, no manual invalidation, no API route
return <div>{user?.name}</div>;
}
Convex vs Traditional Stack (SaaS Specific)
| Feature | Convex | Supabase + Prisma | Firebase |
|---|---|---|---|
| Real-time subscriptions | ✅ Automatic | ✅ Realtime API | ✅ onSnapshot |
| TypeScript types | ✅ First-class | ✅ With Prisma | ⚠️ Generated |
| Schema migrations | ✅ Automatic | ✅ Via Prisma | ❌ |
| Full-text search | ✅ Built-in | ✅ pg_trgm | ⚠️ Limited |
| File storage | ✅ Built-in | ✅ Storage | ✅ |
| Background jobs | ✅ Scheduled functions | ❌ (need pg_cron) | ✅ Functions |
| Rate limiting | ✅ Built-in | ❌ | ❌ |
| Caching | ✅ Automatic query cache | ❌ | ❌ |
| Self-host | ❌ Managed only | ✅ | ❌ |
| Free tier | 1M function calls/month | 500MB database | 1GB storage |
| Pricing (paid) | $25/month | $25/month | Pay-per-use |
Convex's key limitation: it's managed-only — you can't self-host Convex. If data residency or vendor lock-in is a hard requirement, Convex isn't the right choice. For most indie hackers and early-stage startups, the productivity gain outweighs the managed dependency.
Quick Comparison
| Starter | Price | Auth | Billing | Org Support | Stack |
|---|---|---|---|---|---|
| Convex Ents SaaS | Free | Clerk | Stripe | ✅ | Next.js + Convex |
| RSK | Free | Clerk | Polar.sh | ❌ | RR7 + Convex |
| nextjs-starter-kit-convex | Free | Custom | Stripe | ✅ | Next.js + Convex |
| Midday Convex port (v1.run) | Free | Better Auth | Polar.sh | ✅ | Next.js + Convex |
| Convex AI template | Free | NextAuth | ❌ | ❌ | Next.js + Convex |
1. Convex Ents SaaS Next.js Starter — Best Official Option
Price: Free | Creator: Convex team | Stack: Next.js + Convex + Clerk
The official Convex team's SaaS starter using Convex Ents — a relationship management layer that makes working with related data (users → teams → projects) significantly cleaner than raw Convex queries.
What's included:
- Organization/team management with configurable roles
- Member invitation via email (Resend integration)
- Clerk authentication with session sync to Convex
- shadcn/ui with responsive layout
- Dark mode
- TypeScript throughout
- Deployment to Vercel
Convex Ents makes relations easy:
// convex/schema.ts — Define relationships with Ents
import { defineEnt, defineEntSchema } from 'convex-ents';
import { v } from 'convex/values';
export const schema = defineEntSchema({
organizations: defineEnt({
name: v.string(),
slug: v.string(),
})
.edges('members', { to: 'organizationMembers' })
.edges('projects', { to: 'projects' }),
users: defineEnt({
clerkId: v.string(),
email: v.string(),
name: v.optional(v.string()),
})
.edges('memberships', { to: 'organizationMembers' })
.index('by_clerk_id', ['clerkId']),
organizationMembers: defineEnt({
role: v.union(v.literal('owner'), v.literal('admin'), v.literal('member')),
})
.edge('organization', { to: 'organizations' })
.edge('user', { to: 'users' }),
projects: defineEnt({
name: v.string(),
description: v.optional(v.string()),
})
.edge('organization', { to: 'organizations' }),
});
// convex/organizations.ts — Clean relationship queries with Ents
import { query, mutation } from './_generated/server';
import { v } from 'convex/values';
export const getOrganizationWithMembers = query({
args: { slug: v.string() },
handler: async (ctx, { slug }) => {
const org = await ctx.table('organizations')
.filter(q => q.eq(q.field('slug'), slug))
.first();
if (!org) return null;
// Ents handles the join automatically
const members = await org.edge('members');
const membersWithUsers = await Promise.all(
members.map(async (member) => ({
...member,
user: await member.edge('user'),
}))
);
return { ...org, members: membersWithUsers };
},
});
2. RSK (React Starter Kit) — Best Free Convex SaaS Stack
Price: Free (MIT) | Stack: React Router v7 + Convex + Clerk + Polar.sh
RSK pairs Convex with React Router v7 (Remix's successor), Clerk for auth, and Polar.sh for billing — the most modern combination available in a free starter.
// RSK: Real-time dashboard with Convex
// app/routes/dashboard.tsx
import { useQuery } from 'convex/react';
import { api } from '~/convex/_generated/api';
export default function Dashboard() {
// Live subscription — updates when any user's data changes
const metrics = useQuery(api.dashboard.getMetrics, {
organizationId: currentOrgId,
});
// No loading spinners needed for real-time updates
// metrics updates automatically when server data changes
return (
<div>
<MetricCard title="Active Users" value={metrics?.activeUsers ?? 0} />
<MetricCard title="MRR" value={metrics?.mrr ?? 0} />
</div>
);
}
3. nextjs-starter-kit-convex (acelords) — Most Batteries Included
Price: Free (MIT) | Stack: Next.js + Convex + Stripe + AI playground
This community starter is notable for including an AI playground — a pre-built chat interface using Convex for message history and streaming. It covers:
- Dashboard with sidebar navigation
- Authentication routes
- Marketing landing page
- API routes
- AI chat playground (Convex + OpenAI)
- Stripe billing setup
// AI chat with Convex message history
// convex/messages.ts
export const list = query({
args: { conversationId: v.id('conversations') },
handler: async (ctx, { conversationId }) => {
return await ctx.db
.query('messages')
.withIndex('by_conversation', (q) =>
q.eq('conversationId', conversationId)
)
.order('asc')
.collect();
},
});
export const send = mutation({
args: {
conversationId: v.id('conversations'),
content: v.string(),
role: v.union(v.literal('user'), v.literal('assistant')),
},
handler: async (ctx, args) => {
return await ctx.db.insert('messages', {
...args,
createdAt: Date.now(),
});
},
});
4. v1.run (Midday Convex Port) — Most Complete Free Stack
Price: Free (MIT) | Stack: Next.js + Convex + Better Auth + Polar.sh (Turborepo)
v1.run is a Turborepo monorepo modeled after Midday (a well-architected open-source finance app), ported to use Convex instead of Supabase. It's the most architecturally complete free Convex starter with:
- Turborepo monorepo with
apps/web,apps/api,packages/* - Convex for all data storage, background functions, file storage
- Better Auth for authentication (no Clerk dependency)
- Polar.sh billing
- React Email + Resend for transactional email
- Internationalization (next-intl)
- Sentry error tracking pre-configured
- OpenPanel analytics
Convex Patterns Every SaaS Needs
Background jobs (scheduled functions):
// convex/crons.ts — Scheduled functions for SaaS
import { cronJobs } from 'convex/server';
import { internal } from './_generated/api';
const crons = cronJobs();
// Daily job: send trial expiring emails
crons.daily(
'send-trial-expiring-emails',
{ hourUTC: 9, minuteUTC: 0 },
internal.emails.sendTrialExpiringEmails
);
// Weekly job: generate usage reports
crons.weekly(
'generate-usage-reports',
{ dayOfWeek: 'monday', hourUTC: 8, minuteUTC: 0 },
internal.reports.generateWeeklyReports
);
export default crons;
File storage:
// Upload file → store in Convex storage → get URL
export const generateUploadUrl = mutation(async (ctx) => {
return await ctx.storage.generateUploadUrl();
});
export const saveFile = mutation({
args: {
storageId: v.id('_storage'),
filename: v.string(),
},
handler: async (ctx, { storageId, filename }) => {
const url = await ctx.storage.getUrl(storageId);
return await ctx.db.insert('files', {
storageId,
filename,
url: url!,
uploadedAt: Date.now(),
});
},
});
Choosing a Convex SaaS Boilerplate
Official recommended: Convex Ents SaaS Starter — maintained by the Convex team, uses Convex Ents for clean relationship management.
Modern free stack: RSK — React Router v7 + Convex + Clerk + Polar.sh, zero cost, MIT license.
Most features: nextjs-starter-kit-convex — includes AI playground and more complete feature set.
Best architecture: v1.run — Turborepo monorepo with production-grade structure.
Browse all Convex boilerplates at StarterPick.
Related: Best Boilerplates With Polar.sh Payments 2026 · Top AI SaaS Boilerplates 2026
Review SaaS Starter Kit and compare alternatives on StarterPick.
Convex vs Traditional Databases: The Trade-Off to Understand
Choosing a Convex boilerplate means committing to Convex's backend-as-a-service model. That is worth understanding explicitly before starting — the trade-offs are real and not always surfaced clearly in the boilerplate documentation.
What you gain with Convex: The real-time subscriptions are genuinely exceptional. Any query you write in Convex automatically becomes a live subscription — when the underlying data changes, every connected client receives the update without polling, without WebSocket management, and without any additional code. For collaborative SaaS products (shared documents, live dashboards, team inboxes), this is a concrete architectural advantage over PostgreSQL + Supabase Realtime or PostgreSQL + polling. The TypeScript-first design — schema, functions, and queries all in TypeScript — eliminates the impedance mismatch between your data model and your application code. Convex validates all writes against the schema at the database layer, which catches a category of bugs that only appear at runtime in schema-less or lightly typed backends.
What you give up: Convex is a managed service with no self-hosted option. Your data lives on Convex's infrastructure. The query language is Convex's own API rather than SQL — if your team has strong SQL expertise, expect a learning curve. Complex reporting queries (multi-table joins, window functions, aggregations) that SQL handles elegantly require more effort in Convex's document-oriented query model. Convex's pricing is usage-based; for high-volume write applications (real-time games, high-frequency logging), the cost scales faster than a fixed PostgreSQL instance.
When Convex is clearly the right choice: Collaborative tools where multiple users edit shared state simultaneously. Chat applications. Live notification systems. Any product where "who changed what and when" is a core feature — Convex's document history and reactive queries make audit trails nearly free to implement. For these use cases, the productivity gain from Convex's real-time primitives outweighs the trade-offs.
For teams evaluating Convex against PostgreSQL-based alternatives, see the best SaaS boilerplates guide which covers the full landscape including both Convex-native and PostgreSQL-first starters.
Scaling Convex: What Happens as Your SaaS Grows
Convex's pricing model scales with storage, function calls, and bandwidth. Understanding the scaling characteristics before you build prevents architecture surprises at growth.
At low usage (under 1M function calls per month, under 1GB storage), Convex's free tier is generous — most early-stage SaaS products run comfortably without cost. The free tier supports up to 10K concurrent connections, which covers products up to roughly 5,000-10,000 monthly active users depending on session length.
The cost curve steepens as function call volume grows. A SaaS product with 10,000 daily active users making 20 function calls per session generates approximately 6M function calls per month — above the free tier but well within the paid plans. At this usage level, Convex's cost is comparable to running a managed PostgreSQL instance (Supabase, Neon, or PlanetScale) plus the application server — not a significant cost differential in absolute terms.
Where the trade-off becomes visible is in read-heavy workloads. If your SaaS serves large datasets to many concurrent users (analytics dashboards, large list views), the Convex bandwidth cost for repeatedly transmitting the same data can exceed what a PostgreSQL database with a caching layer (Redis or Next.js Data Cache) would cost. The solution is Convex's built-in pagination and query caching — never load more documents than the user needs to see, and structure queries to minimize re-execution.
For teams building on Convex boilerplates, the production SaaS pattern is: start on the free tier, profile your actual function call counts during beta, and project cost at your growth targets before launch. The production SaaS free tools guide covers how to set up monitoring that makes this profiling straightforward.
Convex Authentication Deep Dive
Authentication in Convex-based SaaS boilerplates requires understanding how Convex handles identity — it is different from session-based or JWT auth in a REST API.
Convex does not authenticate users itself. Instead, you configure an external auth provider (Clerk, Auth.js/NextAuth, or Custom JWT) and Convex verifies the JWT token on every function call. The ctx.auth.getUserIdentity() call inside a Convex function returns the authenticated user's information from the token claims. This is secure and stateless — no session storage required in Convex — but it means every Convex query and mutation must explicitly check authentication for protected data.
// convex/projects.ts — authentication inside Convex functions
import { query, mutation } from './_generated/server';
import { v } from 'convex/values';
export const listMyProjects = query({
args: {},
handler: async (ctx) => {
// Get authenticated user from JWT claims
const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new Error('Unauthenticated');
// Query only this user's projects
return await ctx.db
.query('projects')
.withIndex('by_user_id', (q) => q.eq('userId', identity.subject))
.collect();
},
});
export const createProject = mutation({
args: { name: v.string(), description: v.optional(v.string()) },
handler: async (ctx, args) => {
const identity = await ctx.auth.getUserIdentity();
if (!identity) throw new Error('Unauthenticated');
return await ctx.db.insert('projects', {
...args,
userId: identity.subject,
createdAt: Date.now(),
});
},
});
The identity.subject field is the user's unique identifier from the auth provider — Clerk's user ID, or the sub claim from a standard JWT. Using subject as the foreign key in your Convex tables links database records to auth provider identities without storing user records separately (though most boilerplates do store a users table in Convex for profile data like display name and avatar URL).
Clerk's integration with Convex is the most polished available. Clerk issues JWTs that Convex verifies automatically when you add the Clerk Convex template in the Clerk dashboard and configure the issuer domain in your Convex deployment. The Convex Ents SaaS Starter includes this setup fully configured.
Convex Pricing for SaaS Teams
Understanding Convex's pricing structure before launch prevents budget surprises. Convex's pricing has three components: function calls, storage (documents + file storage), and bandwidth.
The free tier covers 1M function calls per month, 512MB document storage, and 1GB bandwidth. This is generous for early-stage products — a SaaS with 200 daily active users making 30 Convex calls per session generates approximately 1.8M function calls per month, slightly over the free tier. The Pro plan at $25/month extends these limits significantly and is the right tier for most growth-stage SaaS products.
The cost structure rewards efficient query design. A dashboard that subscribes to 10 separate Convex queries makes 10 function calls on initial load plus re-execution calls each time any of those queries' data changes. Consolidating those 10 queries into one comprehensive query with joins reduces function call count by 10x, which matters as MAU grows. Designing Convex queries with billing efficiency in mind — not just application correctness — is a habit worth building early.
Convex also offers an actions primitive — functions that can call external APIs, run long-running computation, or use Node.js APIs unavailable in standard Convex functions (which run in Convex's custom V8 environment). Actions are not reactive — they do not update live subscriptions automatically — but they bridge Convex's pure reactive model with the real world. A Stripe webhook handler is a Convex HTTP action. An OpenAI API call that processes user content and stores the result is a Convex action. For boilerplates that need AI features, the actions primitive is how Convex fits into an LLM workflow: the action calls the AI API, streams or stores the result back to the Convex database, and connected React components receive the result via their live subscriptions without any additional plumbing. The best SaaS boilerplates guide covers which full-stack starters include AI features and how they integrate with backend architectures like Convex.
Browse all Convex boilerplates at StarterPick.
See the best SaaS boilerplates guide for the full comparison including Convex vs PostgreSQL starters.
Read the production SaaS free tools guide for the zero-cost stack that complements Convex's free tier.
Check out this boilerplate
View Convex Ents SaaS Starteron StarterPick →