Database hosting

Run Voltro on any hosted Postgres, MySQL, MariaDB, or SQL Server — Supabase, Neon, Vercel Postgres, Railway, Render, Fly.io, AWS RDS, PlanetScale, Azure SQL, and more. Connection strings, pooling, gotchas.

Voltro runs on five SQL backends — postgres, mysql 8+, mariadb 10.6+, mssql 2019+, and sqlite (local file) — plus the beta Turso dialect (the Rust SQLite rewrite, local file or :memory:). Any managed database that speaks one of those dialects works. You set two environment variables — DB_DIALECT and DB_URL — and the framework's schema, queries, workflows, and reactive engine run unchanged.

This page maps the common hosted-database providers to the Voltro dialect they back, the connection shape, and the gotchas worth knowing before you deploy. Each provider has its own page below.

The two-variable contract

DB_DIALECT=postgres                                   # postgres | mysql | mariadb | mssql | sqlite
DB_URL=postgresql://user:pass@host:5432/db?sslmode=require

DB_DIALECT picks the driver; DB_URL is the connection string for the provider. When a single URL doesn't fit, the discrete DB_HOST / DB_PORT / DB_USER / DB_PASSWORD / DB_DATABASE fields are the dialect-agnostic alternative (and PG_HOST / PG_PORT / PG_USER / PG_PASSWORD / PG_DATABASE are accepted as a fallback). Env always wins over app.config.ts's store: field.

Declare your dialect's driver

Each app declares the driver package for its DB dialect as a dependency — the CLI does not bundle every driver, so a production image only ships the one your app actually uses (a memory-store app ships none, and never pulls e.g. turso's ~90 MB native binary):

Dialect Driver package
postgres @voltro/sql-postgres
mysql / mariadb @voltro/sql-mysql
mssql @voltro/sql-mssql
sqlite @voltro/sql-sqlite
turso @voltro/sql-turso
pnpm add @voltro/sql-postgres      # in the app that uses store: 'postgres'

Scaffolded projects already declare the right driver, and voltro add mssql adds @voltro/sql-mssql for you. If a driver is missing at boot, voltro serve fails with a message naming the exact package to install — it never silently falls back. A store: 'memory' app needs no driver.

Providers at a glance

Provider Voltro dialect Pooling Notes
Supabase postgres Supavisor (:6543 txn / :5432 session) LISTEN/NOTIFY needs the session port or a direct connection; the transaction pooler drops it.
Neon postgres PgBouncer (-pooler endpoint) Serverless functions use the pooled endpoint; CDC listener uses the direct endpoint. Branching for preview DBs.
Vercel Postgres postgres Neon-backed pooler Neon under the hood. Same pooled-vs-direct split as Neon.
Railway postgres / mysql none by default Plain managed Postgres or MySQL. Use the private network URL in-cluster.
Render postgres none by default Internal vs external connection strings; internal avoids egress + SSL friction.
Fly.io Postgres postgres none (or pgbouncer app) Unmanaged Postgres app — you own backups + HA. Flycast for internal routing.
AWS RDS / Aurora postgres / mysql / mariadb RDS Proxy (optional) Full LISTEN/NOTIFY on Postgres (direct endpoint for the CDC listener). MariaDB adds binlog CDC; needs a binlog-enabled parameter group.
DigitalOcean postgres / mysql built-in connection pool Pooler in transaction mode drops LISTEN/NOTIFY — add a direct connection for CDC.
Timescale postgres none by default Postgres + the TimescaleDB extension. Full reactive surface; hypertables are opt-in per table.
CockroachDB postgres (wire) built-in Caveat: wire-compatible, NOT feature-compatible. No LISTEN/NOTIFY → no native CDC. Cross-instance reactivity still works via @voltro/plugin-broadcast (Redis / NATS fan-out of app-mutation changes). May not pass all of Voltro's pg DDL. SQL surface only.
PlanetScale mysql built-in (Vitess) Caveats: no native CDC (mysql is inline-only; no binlog access on Vitess) → use @voltro/plugin-broadcast for cross-instance reactivity. Vitess also disables foreign keys by default — enable FK support on the branch or reference() cascades won't apply.
Azure SQL mssql none by default SQL Server 2019+ surface. CDC is inline-only (no native cross-instance feed) — add @voltro/plugin-broadcast for cross-instance reactivity. OUTPUT INSERTED instead of RETURNING; encrypted connection required.
Turso turso (local file) in-process MVCC pool Supported (beta) via @voltro/sql-turso — the Rust SQLite rewrite with MVCC concurrent writes (BEGIN CONCURRENT). Embedded engine: a local file or :memory:, NOT a hosted provider. Remote libSQL / Turso Cloud (libsql://…) is still rejected — that's a libSQL-client concern, not this dialect.

Legend: the dialect column is the value you set for DB_DIALECT. "Pooling" is the connection-pooler the provider ships; it matters because the native Postgres reactive path (LISTEN/NOTIFY CDC) needs a long-lived session-mode connection — transaction-mode poolers silently break it (the broadcast plugin sidesteps that, see below).

The one cross-cutting gotcha: pooling vs LISTEN/NOTIFY

On Postgres, Voltro's low-latency native reactive path uses LISTEN/NOTIFY. That needs a long-lived, session-mode connection. A transaction-mode pooler (Supabase Supavisor :6543, Neon's pooled endpoint, DigitalOcean's transaction pool, RDS Proxy without pinning) hands you a fresh backend per transaction — the LISTEN is registered on a connection you never see again, so change events never arrive.

You have two ways to fix it — pick by what you need:

  1. Keep native CDC — query the CDC listener to a direct / session-mode connection while application queries keep going through the pool. Each provider page below spells out the exact endpoints. This preserves the full Postgres path: low-latency fan-out and capture of out-of-band writes (a psql session, another service touching the DB).

  2. Skip the listener with @voltro/plugin-broadcast — a Redis / NATS pub/sub bus that fans every committed ctx.store mutation out to all replicas. It opens no LISTEN connection, so it works straight through the transaction pooler — and it's the same plugin you'd add for cross-replica reactivity on a multi-pod deployment anyway. Trade-off: the bus carries app-mutation changes, not out-of-band DB writes — only the native LISTEN/NOTIFY path observes those.

MySQL / MSSQL don't have the pooling concern at all — their change path is inline (single-instance) and, for cross-replica fan-out, rides the broadcast plugin. MariaDB adds native binlog CDC (not connection-pinned). SQLite is in-process. See Multi-replica reactivity for the full tier breakdown.

What the dialect page covers vs what these pages cover

These provider pages are about getting connected — the connection string, SSL, pooling, and provider-specific quirks. For the deep dialect surface — RETURNING gaps, CDC mechanics, cluster workflow locks, read-replica routing, JSON handling, identifier quoting — see the underlying SQL dialects section. Every provider page links to its dialect page.