DATABASES / LESSON 12
Convex Basics.
What Convex is, how its documents and functions work, and how it compares to Supabase

Loading the lesson…
Loading activities…
DATABASES / LESSON 12
What Convex is, how its documents and functions work, and how it compares to Supabase

Loading the lesson…
Loading activities…
You just learned how SQL databases like Postgres keep data in tables and rows. Convex goes a totally different way. Your database and your backend code live together, and your app updates itself whenever the data changes.
I've got some skin in this one. Seedly CRM runs on Convex, and building all four Seedly products took me 1,200+ hours and more than $2,000 in AI tokens on Claude Code (my credit card remembers every one of those tokens).
Convex describes itself as "the open source, reactive database where queries are TypeScript code running right in the database."
In normal human words, Convex hands you three things in one spot.
The database gets set up for you automatically when you create a project. The docs keep it simple. There's no connection setup or cluster management.
Convex calls itself a "document-relational" database. Sounds fancy, right? Let's split it in half.
Here's how that lines up with what you learned about Postgres.
| Idea | Postgres (SQL) | Convex |
|---|---|---|
| A group of similar items | Table | Table |
| One item | Row | Document |
| Shape of the data | Columns you define up front | Fields on a JSON-like object |
| Unique ID | Usually an id column you set up | An _id field Convex creates for you |
| How you read and write | SQL (or an ORM like Prisma) | TypeScript functions |
A few things work differently than you might expect.
Tables appear on their own. In Convex, a table "springs into existence as soon as you add the first document to it." You don't have to create it first.
Schemas are optional. A schema describes your tables and what each document should look like. Convex lets you start without one, and the docs actually recommend that for quick prototyping. You add a schema later to keep your data tidy and get better type safety.
Every document gets an ID. Convex automatically adds an _id field (and a _creationTime field) to every document. You can store one document's _id inside another document to link them, like a task that belongs to a user.
Here are three perfectly valid Convex documents, straight from the docs.
Your frontend never talks to the Convex database directly. You write small backend functions, and your app calls those. There are three kinds.
Queries read data. The docs describe them as functions that "read data from your Convex database and are automatically cached and subscribable (realtime, reactive)." A query can ONLY read. It can't change a thing.
Mutations write data. They insert, update and delete documents. Every mutation runs as a transaction, so all of its changes get saved together. If something breaks halfway through, none of the changes get saved.
Actions are for talking to the outside world. The docs say actions "can call OpenAI, Stripe, Twilio, or any other service or API you need to make your app work." Actions can't touch the database on their own. To read or write data, an action calls a query or a mutation.
Here's the quick comparison table from the Convex docs.
| Queries | Mutations | Actions | |
|---|---|---|---|
| Database access | Yes | Yes | No |
| Transactional | Yes | Yes | No |
| Cached | Yes | No | No |
| Real-time Updates | Yes | No | No |
| External API Calls (fetch) | No | No | Yes |
Here's the part that makes Convex feel so different.
When your React component uses a Convex query, it subscribes to that query. Convex keeps track of which data the query read. When any of that data changes, Convex reruns the query and sends the fresh result to your app, and your component re-renders with it.
The docs compare it to React's own useState. useState updates your component when local state changes, and the Convex useQuery hook updates your component when the query result changes. You don't write a single line of code to listen for changes or refresh anything.
Convex keeps things consistent too. If two parts of your page depend on the same data, they update at the exact same moment... so you never see one number changed while the other one is stale.
Both give you a hosted database and live updates, so it's fair to wonder which one to pick. The BIGGEST difference is how you work with your data.
Supabase is built on PostgreSQL. Your data lives in SQL tables with rows and columns, and everything you learned about SQL and Postgres carries right over.
Convex stores JSON-like documents and has no SQL at all. You write your backend logic as TypeScript functions in a convex/ folder, and your app calls those functions. Live updates come built into every query you call through the client library.
| Supabase | Convex | |
|---|---|---|
| Database type | PostgreSQL (SQL) | Document-relational |
| How you work with data | SQL, or a client library | TypeScript query and mutation functions |
| Backend code | Optional | Required, every read and write goes through a function |
| Live updates | You subscribe to changes in your code | Automatic for queries used with useQuery |
As of October 2026, the Convex pricing page lists a free plan called Free & Starter, described as "For personal projects and prototypes," with paid plans above it. Limits and prices can change though, so always check the Convex pricing page before you plan a real project.
_idNext up we'll set up Convex in a real Next.js app, following the official quickstart one step at a time...