azurepostgres SQL dialect (Azure Database for PostgreSQLazurepostgresazurepostgrespg, soAzurePostgresDialect extends PostgresDialect and models only| Property | Value |
|---|---|
| Dialect name | azurepostgres |
| Extends | PostgresDialect |
| Driver | pg |
| Optional SDK | @azure/identity (Entra tokens) |
| Default port | 5432 (6432 for the built-in PgBouncer) |
| Cloud SDK | @azure/identity (Entra only) |
| Local runtime | none — hosted service only |
$ npm install ts-prorm-orm pg$ pnpm add ts-prorm-orm pg$ yarn add ts-prorm-orm pg$ bun add ts-prorm-orm pgpg is the same driver the postgres dialect uses. Add @azure/identity only for the token-based logins under Managed and cloud variants. pg-copy-streams is optional: only the features that need it load it.import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'azurepostgres',
host: 'mypg.postgres.database.azure.com',
database: 'app',
username: 'app',
password: process.env.DB_PASSWORD,
});import { Prorm } from 'ts-prorm-orm';
export const db = new Prorm({
dialect: 'azurepostgres',
url: 'azurepostgres://app:secret@mypg.postgres.database.azure.com:5432/app',
});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) },
meta: { type: DataTypes.JSONB() },
});
await db.sync(); // CREATE TABLE — see Generated SQL belowmeta is JSONB, which the containment query below needs.import { 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: 'azurepostgres',
host: 'mypg.postgres.database.azure.com',
database: 'app',
username: 'ana@contoso.com', // the Entra principal
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: 'azurepostgres',
host: 'mypg.postgres.database.azure.com',
database: 'app',
username: 'ana@contoso.com',
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: 'azurepostgres',
host: 'mypg.postgres.database.azure.com',
database: 'app',
username: 'ana@contoso.com',
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: 'azurepostgres',
host: 'mypg.postgres.database.azure.com',
database: 'app',
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' });upsert() 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,
});meta column:import { Op } from 'ts-prorm-orm';
await User.findAll({ where: { meta: { [Op.contains]: { plan: 'pro' } } } });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(() => {});
});SKIP LOCKED)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 → VARCHAR(255), auto-increment INTEGER → SERIAL, BOOLEAN → BOOLEAN, DATE → TIMESTAMP, UUID → UUID, JSON → JSON. The type comparison lines the major engines up side by side.import { Prorm } from 'ts-prorm-orm';
// Microsoft Entra ID: the user is the principal's name, the password a token
new Prorm({
dialect: 'azurepostgres',
host: 'mypg.postgres.database.azure.com',
database: 'app',
username: 'ana@contoso.com', // or a group / service principal / managed identity display name
dialectOptions: {
entra: true, // or { credential: {...} }, or tokenProvider
},
});
// Password login
new Prorm({
dialect: 'azurepostgres',
host,
database,
username: 'admin',
password: '…',
});entra the dialect builds entraTokenProvider({ target: 'postgres-flexible' })https://ossrdbms-aad.database.windows.net/.default), and itsresolvePoolConfig override spreads pgAuth() into thepassword becomes an async function, so every new connection —LISTEN client — gets a current token.require_secure_transport = ON)ssl is not given the{ rejectUnauthorized: true } with Node's trust store. Withssl is not verified, if username ispassword is also set.AzurePostgresDialect extends PostgresDialect (postgres) andObject.getOwnPropertyNames(AzurePostgresDialect.prototype),| Area | Overridden |
|---|---|
| Connection and execution | resolvePoolConfig |
| DDL and schema | buildCreateEntraPrincipalSql, buildCreateEntraPrincipalWithOidSql, buildCreateRoleQuery, buildCreateUserQuery, createDatabaseSQL, createExtension, createRole, createTable, createUser |
| Introspection | assertNoSuperuser, assertNoTablespace, getAllowedExtensions |
| Other | buildAllowedExtensionsQuery, buildListEntraPrincipalsSql |
azure.extensions allow-listazure.extensionscreateExtension(name) checks first:allowedExtensions when given, otherwiseSELECT current_setting('azure.extensions', true) AS allowed;az postgres flexible-server parameter set --name azure.extensions …getAllowedExtensions() and buildAllowedExtensionsQuery() are public.shared_preload_libraries are left to the server.azure_pg_admin limits, refused by nameazure_pg_admin, aazuresu is Microsoft's).| Call | Refused because |
|---|---|
createUser / createRole / buildCreateUserQuery / buildCreateRoleQuery with superuser: true | Superuser is reserved; use azure_pg_admin membership |
createTable(…, { tablespace }), createDatabaseSQL({ tablespace }) | Tablespaces cannot be created or used |
{ sql, bindings } with $n parameters.| Builder | Function |
|---|---|
buildCreateEntraPrincipalSql(name, { isAdmin, isMfa }) | pg_catalog.pgaadauth_create_principal(roleName, isAdmin, isMfa) |
buildCreateEntraPrincipalWithOidSql(name, oid, type, { isAdmin, isMfa }) | pg_catalog.pgaadauth_create_principal_with_oid(…), type user/group/service |
buildListEntraPrincipalsSql(adminsOnly) | pg_catalog.pgaadauth_list_principals(isAdminValue) |
pg; nothing has run against a live server.CREATE EXTENSION sent through raw query() is not checked; onlycreateExtension() is.CREATE CAST only for azure_pg_adminazure_pg_admin cannot be altered) are left to the server.capabilitiesOf() (src/transaction-support.ts),whereSupportOf() (src/query-builders/expression-render.ts),sqlObjectCapabilitiesOf() (src/sql-objects/capabilities.ts) and the| Capability | azurepostgres |
|---|---|
| Transactions atomic | yes |
| Savepoints | yes |
| Isolation | up to SERIALIZABLE |
| Transaction modes | read-only yes; deferrable yes; constraint deferral yes |
| RETURNING | RETURNING on INSERT |
| Upsert | INSERT … ON CONFLICT (…) DO UPDATE |
| JSON column | JSON (JSONB → JSONB) |
| Vector column | VECTOR(3) |
| Array column | INTEGER[] |
| WHERE builder | 62 operator keys; $and/$or/$not; $exists: yes; $in subquery: yes; expression operands: yes |
| SQL objects | family postgres: triggers yes; procedures yes; functions multiStatement; materialized views native; sequences yes; enums named; RLS policy |
| Streaming | queryStream() present; LISTEN present; createExtension() present |