Skip to content

Join the Seedly owners community →

Databases

Convex Basics

What Convex is, how its documents and functions work, and how it compares to Supabase

Written by 10 min read2 activities
Sprout, your presenter

Sprout presents

Convex trades SQL for TypeScript functions, and every query result updates live. Three function types to learn, which is a pleasingly small number.Convex trades SQL for TypeScript functions, and every query result updates live. Three function types to learn, which is a pleasingly small number.

Sprout changes a tile on a wooden board and three easel paintings change to match
Change the data and every screen updates by itself

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).

What Is Convex?#

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.

  • A database to store your app's data
  • Server functions where your backend code runs
  • Client libraries that hook your frontend (like a React or Next.js app) up to those functions

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.

Documents and Tables vs. SQL Rows#

Convex calls itself a "document-relational" database. Sounds fancy, right? Let's split it in half.

  • Document means each piece of data is a JSON-like object. It has fields and values, and it can hold nested objects and arrays.
  • Relational means documents still live in tables, and one document can point at another one by its ID.

Here's how that lines up with what you learned about Postgres.

IdeaPostgres (SQL)Convex
A group of similar itemsTableTable
One itemRowDocument
Shape of the dataColumns you define up frontFields on a JSON-like object
Unique IDUsually an id column you set upAn _id field Convex creates for you
How you read and writeSQL (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.

{}
{"name": "Jamie"}
{"name": {"first": "Ari", "second": "Cole"}, "age": 60}

Queries, Mutations and Actions#

Your frontend never talks to the Convex database directly. You write small backend functions, and your app calls those. There are three kinds.

Queries#

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#

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#

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.

QueriesMutationsActions
Database accessYesYesNo
TransactionalYesYesNo
CachedYesNoNo
Real-time UpdatesYesNoNo
External API Calls (fetch)NoNoYes

Reactivity, the Big Idea#

Sprout juggles a magnifying glass, a pencil and a brass telephone
Queries read, mutations write, actions call outside services

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.

What This Looks Like in a Chat App#

  1. Someone sends a message, which calls a mutation
  2. The mutation saves the message to the database
  3. Convex notices the "get messages" query depends on that data
  4. Convex reruns the query and pushes the new list to every open app
  5. Everybody's screen shows the new message

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.

How Is Convex Different from Supabase?#

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.

SupabaseConvex
Database typePostgreSQL (SQL)Document-relational
How you work with dataSQL, or a client libraryTypeScript query and mutation functions
Backend codeOptionalRequired, every read and write goes through a function
Live updatesYou subscribe to changes in your codeAutomatic for queries used with useQuery

You Might Pick Supabase When#

  • You want a SQL database and want to use what you learned about Postgres and Prisma
  • Your team already knows SQL
  • You want your data sitting in a standard Postgres database

You Might Pick Convex When#

  • Your whole app is TypeScript and you want the backend in TypeScript too
  • Live updates are central to your app, like chat, dashboards or collaboration tools
  • You'd rather skip writing SQL and setting up an ORM

What Does It Cost?#

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.

TL;DR#

  • Convex gives you a database, server functions and client libraries in one product
  • Data is stored as JSON-like documents inside tables, and every document gets an _id
  • There's no SQL, you read and write data with TypeScript functions
  • Queries read, mutations write as a transaction and actions call outside services
  • Queries are reactive, so your app updates on its own when data changes
  • Supabase is SQL on Postgres, and Convex is documents plus TypeScript functions

What's Next?#

Next up we'll set up Convex in a real Next.js app, following the official quickstart one step at a time...

This lesson ends with 2 short activities.