bedda.tech logobedda.tech
← Back to blog

Convex vs Supabase: 6 Months in Production

Matthew J. Whitney
9 min read
artificial intelligencetypescriptfull-stackbackendjavascript

The Convex vs Supabase decision felt obvious at the time. We were building Nozio — a document workspace product — and the pitch for Convex was almost too clean: reactive queries, end-to-end TypeScript, no polling, no WebSocket management, no thinking about cache invalidation. Just write a query function and your UI stays in sync. For a product where multiple users are editing, commenting, and reacting to documents simultaneously, that sounded like exactly what we needed.

So we committed. We went deep. We built the entire data layer on Convex — schemas, mutations, queries, actions, scheduled functions, file storage. Six months later, we're in production with real users, real load, and real opinions about what that decision actually cost us versus what it bought us.

Some of it is genuinely great. Some of it is a tax you pay every single day and nobody warns you about upfront.


Why We Picked Convex Over Supabase for a TypeScript Full-Stack App

The honest answer is that we were building fast and Convex's developer experience is exceptional in the early stages. You define your schema in TypeScript, and the platform generates fully typed query and mutation functions. There's no ORM layer to configure, no migration files to manage on day one, no separate client library for real-time subscriptions. You call useQuery in React, the data appears, and it stays live.

Supabase is a different animal. It's PostgreSQL under the hood, which means you get the full power of a relational database — joins, indexes, views, raw SQL, pg_vector for AI embeddings, the works. Real-time in Supabase is built on Postgres logical replication through Supabase Realtime, which works well but requires you to think about channels, filters, and reconnection logic. It's more infrastructure to wire together.

For Nozio's use case — document state that multiple users need to see update instantly — Convex's reactive model was genuinely the right abstraction. The question is whether the abstraction holds up when you need to do something it wasn't designed for.


The Real-Time Story: Where Convex Earns Its Keep

Six months in, I'll say this without reservation: Convex's real-time model is the best developer experience I've used for collaborative applications. The way it works is that every useQuery call subscribes to a server-side query function, and Convex automatically re-runs that function and pushes the result to all subscribers whenever the underlying data changes. No polling interval. No WebSocket management. No stale cache.

For Nozio's document list view, presence indicators, and comment threads, this is invisible infrastructure. It just works. We have never written a line of WebSocket code. We have never debugged a race condition between a polling interval and an optimistic update. That is not nothing — that is months of avoided complexity.

The optimistic updates story is also genuinely good. Convex mutations return immediately with an optimistic result, and the UI reflects the change before the server confirms it. When the server confirms, there's no flicker. When the server rejects, it rolls back cleanly. On a product where perceived responsiveness is core to the experience, this matters.


The Lock-In Tax: What Nobody Writes Before You're Committed

Here's where I have to be honest in a way the marketing materials aren't.

Convex is not a database. It's a platform that includes a database. The distinction sounds semantic until you need to do something outside the platform's opinionated boundaries.

There is no raw SQL. This is the one I feel most acutely. Convex's query model is JavaScript functions that call document-oriented APIs. If you want to do something like a complex aggregation — say, counting documents grouped by status across a date range for an analytics dashboard — you're either doing it in JavaScript after fetching more data than you need, or you're writing a scheduled function that pre-computes and stores the result. Both approaches work. Neither is as clean as SELECT status, COUNT(*) FROM documents WHERE created_at > $1 GROUP BY status.

We built Nozio's analytics dashboard with pre-computed aggregates stored in a separate Convex table, updated by a scheduled function every 5 minutes. It works. It's also a design pattern I would never have needed with Supabase, where I'd have written a Postgres function and called it from the edge.

The schema system is powerful but rigid in specific ways. Convex schemas are TypeScript-first and genuinely excellent for keeping your data layer type-safe. But the document model means you think in terms of tables with typed fields, and relationships are expressed as IDs you look up manually. There are no foreign key constraints enforced at the database level. There are no cascading deletes. If you delete a document in Nozio and forget to clean up its associated comments, you have orphaned records and no database-level safety net.

We caught this in code review, not in production. But it required discipline that a relational database with constraints would have enforced automatically.

Vendor portability is essentially zero. This is the big one. If Convex changes its pricing tomorrow, or gets acquired, or goes down for four hours, our data layer doesn't run anywhere else. Supabase, by contrast, is built on Postgres — a database you can run yourself, on RDS, on any cloud. The Supabase self-hosting path is real. You can take your data and go. With Convex, your query functions are Convex-specific JavaScript, your schema is Convex-specific, and your real-time subscriptions are Convex-specific. Migration is a rewrite.

I'm not saying this to be alarmist — Convex is a well-funded company and the platform has been reliable for us. But this is the cost you're accepting, and you should accept it consciously.


The AI Integration Question: Convex vs Supabase for Vector Search and LLM Workflows

This is increasingly relevant because Nozio has AI features — document summarization, semantic search across a user's workspace. When we built those features, the data layer choice mattered.

Supabase has pg_vector built in. You store embeddings as a column type, you create an HNSW or IVFFlat index, and you query with <-> distance operators in SQL. It's the most natural integration path for vector search if you're already on Postgres, and the ecosystem of tools that assume Postgres — LangChain, LlamaIndex, pgvector clients — just works.

Convex doesn't have native vector search in the same sense. For Nozio's semantic search, we ended up using Convex Actions — which are functions that can call external APIs — to query a separate vector store. It works, but it's an extra service to manage and an extra network hop on every search query.

If your product is AI-first and vector search is core infrastructure, this is a genuine point in Supabase's favor. The SQL ecosystem for AI tooling is deep and mature, and fighting against it by using a non-SQL backend adds friction you'll feel on every AI feature.


TypeScript Developer Experience: The Score After 6 Months

On pure TypeScript developer experience, Convex is still the winner for us. The end-to-end type safety — from schema definition through to the React hook return type — is genuinely better than anything I've used. Supabase's generated types from supabase gen types typescript are good, but they're a generation step you run, not a live inference. With Convex, if you change a field name in your schema, every query and mutation that touches that field breaks at compile time, immediately, in your editor.

For a team moving fast on a TypeScript full-stack application, that feedback loop is valuable. We've caught schema changes breaking query logic before they ever hit a branch build. That's the kind of thing that sounds minor until it saves you from a production incident at 11pm.

The Convex dashboard is also genuinely useful — you can inspect function logs, query your tables, and watch real-time function executions. It's the kind of tooling that makes debugging feel like a first-class concern.


Where I'd Make a Different Call Today

If I were starting Nozio from scratch today, the decision is closer than it was six months ago, and it depends on what I know now about the product.

Choose Convex if: Real-time collaboration is your core feature, your data model is document-oriented, you're TypeScript-first, and you're willing to accept vendor dependency in exchange for dramatically reduced infrastructure complexity. The early velocity is real. The real-time model is genuinely excellent.

Choose Supabase if: You need complex querying, analytics, or reporting. You're building AI-native features where vector search is first-class. You need the portability of Postgres. You have a team that knows SQL and will be more productive with it than with a JavaScript query API.

The honest version of the Convex vs Supabase analysis is that Convex wins on developer experience for a specific class of application — collaborative, real-time, TypeScript-heavy — and Supabase wins on flexibility, portability, and ecosystem depth for everything else. The mistake is picking Convex because the demo is impressive without asking whether your data access patterns fit the model it's optimized for.

We're staying on Convex for Nozio because the migration cost is now higher than the ongoing tax of working around its limitations. That's a decision I can live with. But I'd make sure you can say the same before you're six months in.


The Actual Verdict

Real-time without polling: Convex wins, and it's not close.

TypeScript full-stack type safety: Convex wins.

Complex queries and analytics: Supabase wins.

AI/ML integration and vector search: Supabase wins.

Vendor portability and long-term risk: Supabase wins.

Early development velocity: Convex wins.

Production flexibility: Supabase wins.

The Convex vs Supabase question doesn't have a universal answer, and anyone who tells you otherwise is selling you something. What I can tell you is that after six months in production on Nozio, I know exactly what I traded and exactly what I got. The real-time model is as good as advertised. The lock-in is as real as the skeptics warned. Both things are true simultaneously, and your job is to decide which one matters more for what you're building.

Have Questions or Need Help?

Our team is ready to assist you with your project needs.

Contact Us