https://www.convex.dev/

Characteristics

  • Backend in TypeScript
  • Live queries by default
    • In Supabase you have to do subscription manually and call UI update function.
    • This is similar to firebase, but you define the backend endpoints (like tRPC)
  • Full type safety with TypeScript
    • Better than Supabase

YouTube | Web Dev Cody | # Why I use Convex over Supabase as my BaaS

Tips

  • Tip: Use a separate project for dev and prod environment
    • With convex auth, it uses SITE_URL environment variable as the redirect URL. Unlike Supabase which supports multiple within the same project, convex seems to support only one. So use separate project with different env vars.
  • It’s possible to integrate convex with Hono

Pros

  • Generous free tier (unlike Supabase which provides only 2)
    • You can create many projects as long as the total storage is not exceeded, this is nice for development (need dev, stage, prod env) and experiments
    • I understand Supabase, their project requires hosting 10+ containers (look at their docker-compose.yml for self hosting). Their cost for a single project is so high.

      Services

      • A Postgres DB
      • kong for load balancing
      • supabase/studio
      • timberio/vector: for logs
      • supabase/supavisor
      • supabase/edge-runtime for edge functions
      • supabase/logflare: for analytics
      • supabase/postgres-meta
      • darthsim/imgproxy: for resizing and converting images
      • supabase/storage-api: for storing files
      • supabase/realtime
      • postgrest/postgrest: supabase-rest container for rest API
      • supabase/gotrue for supabase auth service
      Link to original
    • Convex’s docker-compose.yml for self hosting has only 2 containers, one for backend DB and one for dashboard
      • There are more services in Supabase but Convex does most of them with only 2 containers
  • Live queries with zero effort
  • In the Cons Section below, I talked about Convex’s strong coupling issue, but there is a solution to that
    • Convex provides client libraries for multiple major languages/frameworks: JS/Swift/Python/Android Kotlin/Rust and Svelte/React/TanStack Query/vue
    • OpenAPI
      • Client sdks are causing coupling but convex supports OpenAPI which helps providing supports for other languages like Go, Java, etc.
    • If you really want to migrate away from Convex, try gradually swapping everything in client with OpenAPI generated client sdk, then swap out the backend, so you don’t need to migrate everything at once.

Cons

  • Unknown max-capability
    • Unlike mature Postgres, this is a new DB, we don’t know how well it can scale and handle extreme traffic
  • Strong coupling (Harder to migrate)
    • One drawback of using BaaS like Supabase and Firebase is strong coupling for frontend and backend
      • You have to use BaaS’s client SDK in frontend, making it harder to migrate backend in the future if a bottleneck is reached. Convex is no exception.
    • Supabase is using Postgres under the hood, to migrate away from Supabase
      • I can gradually remove supabase client sdk usage in frontend and switch to use a conventional REST API backend, and use ORM like drizzle to connect to Supabase’s Postgres DB
      • Finally the backend can be fully migrated to another backend framework or even DB, because the coupling between frontend and backend is replaced by the most common REST API/OpenAPI (or graphQL or gRPC).
    • Convex has better DX than Supabase at the cost of even stronger coupling.
      • There is pretty much no way to migrate to another design without rewriting everything. The DB is not like Postgres which you can host in other places. With Supabase, we can swap the Supabase’s Postgres with another Postgres gradually and migrate away from Supabase, but not with Convex.
  • Performance bottleneck
    • Suppose I have a table with 2 fields, id and data. I want to select only all ids from this table, and each data field has 1MB of data. There are 1000 rows. Will the backend fetch all data which is 1GB of data, extract IDs and return to frontend?

    • In Convex, when you query a table, the database always reads entire documents (including all fields) even if you only need specific fields in your result. Based on your example with a table containing 1000 rows where each row has an ID field and a 1MB data field, here’s what would happen: When you query to get only the IDs, Convex would:

      1. Read all 1000 complete documents (including the 1MB data fields)
      2. Extract just the IDs in your query function
      3. Return only those IDs to the frontend

      As noted in the documentation: “Note that in Convex, even with QueryStreams, database queries always read entire documents. They can remove or modify fields in code before returning them to the client.” Translate SQL into Convex Queries

When?

When would I pick this BaaS?

  • Most of the time I think I would pick this
  • Very convenient for small projects with mostly CRUD operations
  • Need live queries

When would I not pick this BaaS?

  • The app could potentially get a huge amount of data, then this DB may not be as good as mature DB like Postgres
    • Mature databases have known solutions for horizontal/vertically scaling through partitioning/sharding
  • Need very complex queries
    • I am not sure about the performance with this DB against complex queries
      • Their filtering/joining/aggregation logic are written in JS/TS
      • The queries code is executed within the DB environment though, so there is negligible network latency (which is the largest cost in most simple queries)
        • In a traditional backend setup: Frontend Backend Database Backend Frontend
        • If the backend and database are not placed in the same data center the network latency could be higher than actual computation time in DB
      • But I doubt if it can be as performant as SQL queries as SQL has been optimized for years
      • Convex’s backend is written in Rust BTW