azuresqlmi SQL dialect (Azure SQL Managed Instance).azuresqlmiazuresqlmiUSE,AzureSQLMIDialect extends MSSQLDialect — notAzureSQLDialect, whose single-database refusals do not apply —| Property | Value |
|---|---|
| Dialect name | azuresqlmi |
| Extends | MSSQLDialect |
| Driver | mssql (tedious) |
| Optional SDK | @azure/identity (Entra tokens) |
| Default port | 1433 (VNet-local); 3342 with publicEndpoint |
| Cloud SDK | @azure/identity (Entra only) |
| Local runtime | none — hosted service only |
$ npm install ts-prorm-orm mssql$ pnpm add ts-prorm-orm mssql$ yarn add ts-prorm-orm mssql$ bun add ts-prorm-orm mssqlmssql is the same driver the mssql dialect uses. Add @azure/identity only for the token-based logins under Managed and cloud variants.import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'azuresqlmi',
host: 'mi1.abc123.database.windows.net',
database: 'sales',
username: 'app',
password: process.env.DB_PASSWORD,
});import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'azuresqlmi',
url: 'azuresqlmi://app:secret@mi1.abc123.database.windows.net:1433/sales',
});host, port, database, username and password before the dialect is built; any of those passed alongside it wins.import { DataTypes } from 'ts-prorm-orm';
const User = db.define('User', {
id: { type: DataTypes.INTEGER(), primaryKey: true, autoIncrement: true },
email: { type: DataTypes.STRING(255), allowNull: false, unique: true },
name: { type: DataTypes.STRING(100) },
});
await db.sync(); // CREATE TABLE — see Generated SQL belowimport { Op } from 'ts-prorm-orm';
await User.create({ email: 'ada@example.com', name: 'Ada' });
const page = await User.findAll({
where: { name: { [Op.like]: 'A%' } },
order: [['id', 'ASC']],
limit: 20,
offset: 40,
});import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'azuresqlmi',
host: 'mi1.abc123.database.windows.net',
database: 'sales',
dialectOptions: {
entra: true, // DefaultAzureCredential: env, workload/managed identity, Azure CLI
},
});@azure/identity installed next to the driver.import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'azuresqlmi',
host: 'mi1.abc123.database.windows.net',
database: 'sales',
dialectOptions: {
entra: { credential: { type: 'managed-identity', clientId: process.env.AZURE_CLIENT_ID } },
},
});@azure/identity installed next to the driver.import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'azuresqlmi',
host: 'mi1.abc123.database.windows.net',
database: 'sales',
dialectOptions: {
entra: {
credential: {
type: 'client-secret',
tenantId: process.env.AZURE_TENANT_ID!,
clientId: process.env.AZURE_CLIENT_ID!,
clientSecret: process.env.AZURE_CLIENT_SECRET!,
},
},
},
});@azure/identity installed next to the driver.import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'azuresqlmi',
host: 'mi1.abc123.database.windows.net',
database: 'sales',
username: 'app',
password: process.env.DB_PASSWORD,
});query(), captured with the driver stubbed out. The model layer inlines the values.db.sync() for the model in the Quick start:CREATE TABLEawait User.create({ email: 'ada@example.com', name: 'Ada' });
await User.update({ name: 'Grace' }, { where: { email: 'ada@example.com' } });
await User.destroy({ where: { id: 1 } });await User.upsert({ id: 1, email: 'ada@example.com', name: 'Ada Lovelace' });MERGE statementupsert() also reads the row by primary key before and after the write, to return the instance.await User.findAll({
where: { name: { [Op.like]: 'A%' } },
order: [['id', 'ASC']],
limit: 20,
offset: 40,
});await db.transaction(async (t) => {
await User.create({ email: 'grace@example.com', name: 'Grace' }, { transaction: t });
// A nested transaction is a SAVEPOINT; its failure undoes only its own work.
await db
.transaction(async (sp) => {
await User.destroy({ where: { id: 1 }, transaction: sp });
throw new Error('keep the row');
}, { transaction: t })
.catch(() => {});
});READPAST)lock with skipLocked inside a transaction:await db.transaction(async (t) => {
await User.findAll({ where: { name: 'Ada' }, lock: { level: 'UPDATE', skipLocked: true }, transaction: t });
});STRING → NVARCHAR(255), auto-increment INTEGER → INT, BOOLEAN → BIT, DATE → DATETIME2, UUID → UNIQUEIDENTIFIER, JSON → NVARCHAR(MAX). The type comparison lines the major engines up side by side.import { Prorm } from 'ts-prorm-orm';
new Prorm({
dialect: 'azuresqlmi',
host: 'mi1.abc123.database.windows.net', // VNet-local endpoint, port 1433
database: 'sales',
dialectOptions: {
entra: true, // or entra: { credential }, tokenProvider, authentication, username/password
},
});
new Prorm({
dialect: 'azuresqlmi',
host: 'mi1.public.abc123.database.windows.net',
database: 'sales',
dialectOptions: {
publicEndpoint: true, // port 3342, fixed by the service
entra: true,
},
});AzureTediousAuthPlan): Entra tokens are wired throughtediousAuth() in the resolvePoolConfigAZURE_SQL_RETRY_DEFAULTS) apply too.AzureSQLMIDialect extends MSSQLDialect (mssql) andObject.getOwnPropertyNames(AzureSQLMIDialect.prototype),| Area | Overridden |
|---|---|
| Connection and execution | connect, query, resolvePoolConfig |
| DDL and schema | buildCreateEntraContainedUserSql, buildCreateEntraLoginSql |
| Introspection | assertSupportedStatement |
| Other | blobUrls, buildBackupToUrlSql, buildRestoreFromUrlSql |
USE, cross-database three-part names, SQL Server Agent jobs (T-SQL and SSISCREATE LOGIN (SQL and Entra). The inherited SQL ServerCREATE LOGIN … ; CREATE USER … FOR LOGIN user builder is kept.query() checks each statement (literals and comments ignored); turn off withstatementGuard: false.| Statement | Why / alternative |
|---|---|
BACKUP LOG | Log backups are automatic; use point-in-time restore |
BACKUP DATABASE … TO DISK/TAPE | Only TO URL (Azure Blob storage) |
BACKUP DATABASE without COPY_ONLY | COPY_ONLY is mandatory |
BACKUP DATABASE … DIFFERENTIAL | Only full backups |
RESTORE … FROM DISK/TAPE, RESTORE LOG | Only FROM URL |
CREATE LOGIN … FROM WINDOWS | Use CREATE LOGIN … FROM EXTERNAL PROVIDER |
| Builder | SQL |
|---|---|
buildBackupToUrlSql(db, urls, { checksum, compression, stats }) | BACKUP DATABASE [db] TO URL = '…'[, URL = '…'] WITH COPY_ONLY[, …] — 1–32 https stripes |
buildRestoreFromUrlSql(db, urls) | RESTORE DATABASE [db] FROM URL = '…' (no WITH options accepted) |
buildCreateEntraLoginSql(name, { databaseUser }) | CREATE LOGIN [name] FROM EXTERNAL PROVIDER[; CREATE USER [name] FROM LOGIN [name]] |
buildCreateEntraContainedUserSql(name) | CREATE USER [name] FROM EXTERNAL PROVIDER |
json type isvector requires Always-up-to-date.mssql; nothing has run against a live instance.json/vector are notsp_configure,CREATE DATABASE without file options, ALTER DATABASE options thatcapabilitiesOf() (src/transaction-support.ts),whereSupportOf() (src/query-builders/expression-render.ts),sqlObjectCapabilitiesOf() (src/sql-objects/capabilities.ts) and the| Capability | azuresqlmi |
|---|---|
| Transactions atomic | yes |
| Savepoints | yes (no explicit RELEASE) |
| Isolation | up to SERIALIZABLE; native levels SNAPSHOT |
| Transaction modes | read-only no; deferrable no; constraint deferral no |
| RETURNING | OUTPUT INSERTED.… on INSERT |
| Upsert | MERGE INTO … WHEN MATCHED / WHEN NOT MATCHED |
| JSON column | NVARCHAR(MAX) (JSONB → NVARCHAR(MAX)) |
| Vector column | VECTOR(3) |
| Array column | NVARCHAR(255) |
| WHERE builder | 18 operator keys; $and/$or/$not; $exists: no; $in subquery: no; expression operands: no |
| SQL objects | family mssql: triggers yes; procedures yes; functions multiStatement; materialized views emulated (indexedView); sequences yes; enums check; RLS no |
| Streaming | queryStream() present; LISTEN absent; createExtension() present |