Skip to main content

One post tagged with "sqlx"

View All Tags

Why TeaQL Supports Both SQLx and rusqlite

· 2 min read
TeaQL Code Gen
Core Contributor

TeaQL Rust supports both SQLx and rusqlite because they solve different deployment problems.

This is not duplication. It is provider choice.

The generated business API should remain stable while the runtime provider changes underneath.

SQLx: Async Backend Services

SQLx is a strong fit for async server-side Rust services.

TeaQL uses SQLx providers for:

  • PostgreSQL;
  • MySQL;
  • SQLite.

SQLx fits services that already run inside an async runtime, use connection pools, and need production backend behavior such as transactions, schema bootstrap, row decoding, and database-specific SQL execution.

Good SQLx targets:

  • API servers;
  • backend services;
  • PostgreSQL business systems;
  • MySQL enterprise systems;
  • local-first services that still use async SQLite.

rusqlite: Embedded SQLite

rusqlite is a strong fit for synchronous embedded SQLite.

That matters for deployments where the database is not a remote backend service:

  • routers;
  • edge devices;
  • appliance controllers;
  • offline local tools;
  • multi-architecture devices;
  • small embedded runtimes;
  • local agent memory.

In those cases, an async pool-oriented provider may be unnecessary weight. A synchronous SQLite provider can be easier to deploy and reason about.

Same Business API, Different Provider

The application should still use generated APIs:

let rows = Q::orders()
.select_self()
.select_line_item_list_with(Q::line_items().select_self())
.execute_for_list(&ctx)
.await?;

The question of SQLx SQLite versus rusqlite SQLite should be a runtime decision, not a reason to rewrite business query code.

Provider Boundary

The boundary looks like this:

Generated Q API
-> UserContext
-> Repository API
-> SQLx PostgreSQL / SQLx MySQL / SQLx SQLite / rusqlite SQLite

This keeps database execution below generated business intent.

Choosing Between Them

Use SQLx when:

  • the app is async;
  • the database is part of a backend service;
  • pooling and async transactions matter;
  • the provider is PostgreSQL or MySQL;
  • SQLite is used in an async service/test path.

Use rusqlite when:

  • SQLite is embedded;
  • sync execution is simpler;
  • deployment footprint matters;
  • the target is edge, device, or local runtime;
  • the app should avoid an async database stack.

Why This Matters for TeaQL

TeaQL is not only about database support. It is about keeping domain APIs independent of storage execution.

Supporting both SQLx and rusqlite lets the same generated model fit more deployment shapes without changing the programming model.