Voltro + Azure SQL

Connect Voltro to Azure SQL Database — the mssql dialect, encrypted connection string, OUTPUT INSERTED instead of RETURNING, cross-instance reactivity via @voltro/plugin-broadcast, and firewall rules.

Azure SQL Database is SQL Server in the cloud, so it uses Voltro's mssql dialect (SQL Server 2019+ surface). The schema DSL, queries, and workflows work; the framework handles the SQL-Server-specific idioms for you (OUTPUT INSERTED instead of RETURNING, OFFSET … FETCH NEXT instead of LIMIT, BIT booleans, [bracket] identifier quoting).

Connect

Azure SQL connections must be encrypted. Set the dialect and a single DB_URL — the mssql layer parses mssql:// (and sqlserver://) connection strings:

DB_DIALECT=mssql
DB_URL=mssql://[USER]:[PASSWORD]@[SERVER].database.windows.net:1433/[DB]

Azure requires the username in user@server form, so URL-encode the @ in the user segment (%40) — e.g. mssql://app%40myserver:pw@myserver.database.windows.net:1433/mydb. TLS on port 1433 is mandatory; the @effect/sql-mssql driver encrypts by default, which matches Azure's requirement.

If a single URL doesn't fit, use the discrete DB_HOST / DB_PORT / DB_USER / DB_PASSWORD / DB_DATABASE env vars instead — these are the dialect-agnostic connection fields the CLI reads. (There are no MSSQL_* env vars.)

Reactivity — inline by default, cross-instance via the broadcast bus

SQL Server has no LISTEN/NOTIFY equivalent, so the mssql dialect emits change events inline: the writing instance emits its own change events in-process (no database-level notify channel). The practical shape:

  • Reactivity works within a single instance out of the box — one Voltro process pushes its own writes to its subscribers. Nothing to enable; it's the default.
  • Cross-instance reactivity needs a pub/sub bus. A write on instance A doesn't wake subscriptions on instance B unless you add @voltro/plugin-broadcast (Redis / NATS). The bus fans out each app-mutation change event to every replica — the cross-instance path mssql lacks natively.
// app.config.ts
import { broadcastPlugin } from '@voltro/plugin-broadcast'
export default { type: 'api' as const, name: 'api', plugins: [broadcastPlugin()] }
// BROADCAST_URL=redis://… (or nats://…)

Caveat: the bus carries app-mutation changes (writes through ctx.store), not out-of-band DB writes — see Multi-replica reactivity. If you need out-of-band-write reactivity too, postgres (LISTEN/NOTIFY) is the right dialect.

Dialect behavior

The MSSQL dialect differs from Postgres in ways the framework abstracts:

  • No RETURNING — the framework uses OUTPUT INSERTED.* / OUTPUT DELETED.*.
  • No LIMIT N OFFSET N — compiled to OFFSET N ROWS FETCH NEXT M ROWS ONLY.
  • JSON columns stored as NVARCHAR(MAX), returned as strings — the framework auto-parses them.
  • Cluster workflows use sp_getapplock for shard ownership.

See the MSSQL dialect page for the complete surface, including the upstream cluster patches.

Firewall rules

Azure SQL blocks all traffic by default. Add your app's outbound IP (or "Allow Azure services") to the server's firewall rules, or connections fail before authentication.

Verify

[voltro:dev] sql dialect resolved: mssql — CDC: inline only, RETURNING: OUTPUT INSERTED/DELETED
[voltro:dev] workflow engine: cluster-sql, dialect=mssql, runnerStorage=sql

Confirm with voltro logs --tail 50.

See also