StitchDB vs Convex: Postgres and SQL or Reactive TypeScript?
Convex and StitchDB are both "backend in a box" platforms, but they ask you to think differently. Convex is TypeScript all the way down: you write queries and mutations as functions, and the client re-renders when the data a query read changes. StitchDB is Postgres underneath: you design tables, write access rules in SQL, and get REST, GraphQL and realtime change streams generated from the schema. Convex gives you the smoothest reactive developer experience; StitchDB gives you SQL, standard tools and flat pricing that does not grow with your team size.
#Summary
| Convex | StitchDB | |
|---|---|---|
| Data model | Documents in tables, optional schema, relational data model | Postgres tables, constraints, foreign keys, jsonb |
| Server logic | TypeScript query, mutation and action functions | SQL functions, triggers, Deno Edge Functions, background jobs |
| Reactivity | Automatic: query subscriptions update on a consistent snapshot | Realtime Postgres changes per table, broadcast, presence |
| Access control | Code in your functions | Row level security policies |
| SQL access | No SQL to write | Full SQL, direct Postgres connections |
| Scheduling | Scheduled functions and cron jobs | pg_cron, durable background jobs |
| Pricing (as of November 2026) | Free & Starter; Professional $25 per developer/mo | Free; Pro $15.99/mo; Scale $49/mo |
| Self-host | Yes, open source backend (FSL Apache 2.0) | No |
#The same feature, built twice
A chat room: list messages in a room, live, and let signed-in users post.
#On Convex
// convex/messages.ts
import { query, mutation } from './_generated/server'
import { v } from 'convex/values'
export const list = query({
args: { roomId: v.id('rooms') },
handler: async (ctx, { roomId }) =>
ctx.db.query('messages')
.withIndex('by_room', (q) => q.eq('roomId', roomId))
.collect(),
})
export const send = mutation({
args: { roomId: v.id('rooms'), body: v.string() },
handler: async (ctx, { roomId, body }) => {
const identity = await ctx.auth.getUserIdentity()
if (!identity) throw new Error('Not signed in')
await ctx.db.insert('messages', { roomId, body, author: identity.subject })
},
})// in a React component
const messages = useQuery(api.messages.list, { roomId })That is the whole live list. Convex tracks that list read the messages index for this room and pushes a new result when a matching message is inserted.
#On StitchDB
create table public.messages (
id bigint generated always as identity primary key,
room_id uuid not null references public.rooms on delete cascade,
author_id uuid not null default auth.uid() references auth.users,
body text not null check (length(body) between 1 and 4000),
created_at timestamptz not null default now()
);
create index on public.messages (room_id, created_at);
alter table public.messages enable row level security;
create policy "members read" on public.messages for select to authenticated
using (exists (select 1 from public.room_members m
where m.room_id = messages.room_id and m.user_id = auth.uid()));
create policy "members post" on public.messages for insert to authenticated
with check (author_id = auth.uid() and exists (
select 1 from public.room_members m
where m.room_id = messages.room_id and m.user_id = auth.uid()));
alter publication stitchdb_realtime add table public.messages;const { data: messages } = await stitchdb
.from('messages').select('id, body, author_id, created_at')
.eq('room_id', roomId).order('created_at')
stitchdb.channel('room-' + roomId)
.on('postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'messages', filter: 'room_id=eq.' + roomId },
(p) => setMessages((m) => [...m, p.new]))
.subscribe()
await stitchdb.from('messages').insert({ room_id: roomId, body: 'Hello' })More lines, and you merge changes into state yourself. In exchange: the length check and the membership rule are enforced by the database for every client and every API, realtime subscribers only receive rows the read policy allows, and the data is in standard Postgres. See Postgres changes and row level security.
#Reactivity and consistency
Convex's reactivity is its signature feature. Every subscription updates to the same database snapshot at the same time, so two components never show contradictory states. Rebuilding that on any table-stream system takes care.
StitchDB's realtime is lower-level and more general: Postgres changes, broadcast for ephemeral messages such as cursors, presence for who is online, broadcast from SQL inside triggers, and message history so a reconnecting client gets missed broadcasts in order. For collaborative editing there are Yjs-based collaborative documents. It covers more use cases; it asks more of you for a simple live query.
#Server logic
Convex keeps all logic in TypeScript functions, with actions for calling external APIs, plus scheduled functions and cron jobs.
StitchDB splits it: rules and data logic in SQL (policies, constraints, triggers, functions callable with rpc()), and integration logic in Edge Functions on Deno with npm imports. Long work goes into background jobs, where each step runs once and is saved, failing steps retry, and runs can sleep for days. Teams that like SQL find this cleaner; teams that want one language may prefer Convex.
#Pricing for a growing team
Convex's Professional plan is $25 per developer per month, with 25M function calls, 50 GB of database storage and 50 GB of bandwidth included. The free plan allows 1 to 6 developers with 1M function calls and 0.5 GB of database storage (as of November 2026; see convex.dev/pricing).
StitchDB plans are per account, not per seat (as of November 2026):
- Free: $0, 2 team members, 500 MB database per project, 25 GB egress.
- Pro: $15.99/month, 10 team members, 10 GB database, 1 TB egress, 2M Edge Function invocations.
- Scale: $49/month, 100 team members, 20 GB database, 2 TB egress, 5M invocations.
For five developers on paid plans, that is $125/month on Convex Professional versus $15.99 or $49 on StitchDB. The units differ (Convex counts function calls; StitchDB limits API requests per second and does not meter database reads), so compare with your own workload. Paid StitchDB plans start with a spend cap on. See pricing.
#Portability
Convex's backend is open source under FSL Apache 2.0 and can be self-hosted, and you can export data as a zip. StitchDB cannot be self-hosted, but every plan can export the full project (pg_dump, users with bcrypt hashes, files, function source), and any Postgres tool connects directly. Your schema and policies are plain SQL that runs on any Postgres.
#Tooling and ecosystem
Convex has a polished CLI and dashboard, generated TypeScript types from your functions, and React hooks that make the reactive model feel native. Its ecosystem is Convex-specific.
StitchDB's tooling is Postgres-shaped: the stitchdb CLI for local development, migrations and preview branches, types for TypeScript, Dart, Swift and Kotlin generated from the schema, and an MCP server so AI coding tools can read your schema and run SQL. Because it is Postgres, everything else in that ecosystem also works: Prisma, Drizzle, psql, BI tools and migration tools like Flyway.
#Trade-offs to know
- StitchDB: EU-only regions; a young platform; no automatic query-level reactivity; no self-hosting.
- Convex: per-developer pricing on Professional; no SQL for BI tools or other services without exporting; logic and access rules live in your TypeScript code rather than the database.
#Which one should you choose?
Choose Convex if your team is TypeScript-first, wants reactive queries with no subscription code, and is small or happy with per-developer pricing.
Choose StitchDB if you want SQL and Postgres, access rules enforced by the database, standard tools, flat team pricing, EU hosting, or built-in services like push notifications, purchase checks and feature flags.
More options are in Convex alternatives, and a Postgres-to-Convex view is in Supabase vs Convex.
#FAQ
#Does StitchDB have something like Convex's useQuery?
Not as one hook. You load data with the SDK and subscribe to table changes with Realtime; offline sync can also keep a live local copy of chosen tables.
#Is Convex a relational database?
Convex describes a relational data model with documents in tables, but you write queries in TypeScript instead of SQL.
#Can I use Prisma or Drizzle with StitchDB?
Yes. Any Postgres ORM connects through the pooler on port 6543 (transaction mode) or 5432 (session mode).
#Which is cheaper for a team of five?
As of November 2026, Convex Professional is $25 per developer per month; StitchDB Pro is $15.99 per month for the account with up to 10 team members.
Try the Postgres side of the trade-off: create a free StitchDB project.