azure-postgres-ts

tarafından microsoft

Connect to Azure Database for PostgreSQL Flexible Server from Node.js/TypeScript using the pg (node-postgres) package. Use for PostgreSQL queries, connection pooling, transactions, and Microsoft Entra ID (passwordless) authentication. Triggers: "PostgreSQL", "postgres", "pg client", "node-postgres", "Azure PostgreSQL connection", "PostgreSQL TypeScript", "pg Pool", "passwordless postgres".

npx skills add https://github.com/microsoft/skills --skill azure-postgres-ts

Azure PostgreSQL for TypeScript (node-postgres)

Connect to Azure Database for PostgreSQL Flexible Server using the pg (node-postgres) package with support for password and Microsoft Entra ID (passwordless) authentication.

Installation

npm install pg @azure/identity
npm install -D @types/pg

Environment Variables

# Required
AZURE_POSTGRESQL_HOST=<server>.postgres.database.azure.com
AZURE_POSTGRESQL_DATABASE=<database>
AZURE_POSTGRESQL_PORT=5432

# For password authentication
AZURE_POSTGRESQL_USER=<username>
AZURE_POSTGRESQL_PASSWORD=<password>

# For Entra ID authentication
AZURE_POSTGRESQL_USER=<entra-user>@<server>   # e.g., user@contoso.com
AZURE_POSTGRESQL_CLIENTID=<managed-identity-client-id>  # For user-assigned identity
AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in production

Authentication

Option 1: Password Authentication

import { Client, Pool } from "pg";

const client = new Client({
  host: process.env.AZURE_POSTGRESQL_HOST,
  database: process.env.AZURE_POSTGRESQL_DATABASE,
  user: process.env.AZURE_POSTGRESQL_USER,
  password: process.env.AZURE_POSTGRESQL_PASSWORD,
  port: Number(process.env.AZURE_POSTGRESQL_PORT) || 5432,
  ssl: { rejectUnauthorized: true }  // Required for Azure
});

await client.connect();

Option 2: Microsoft Entra ID (Passwordless) - Recommended

import { Client, Pool } from "pg";
import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";

// Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS=<specific_credential>
const credential = new DefaultAzureCredential({requiredEnvVars: ["AZURE_TOKEN_CREDENTIALS"]});
// Or use a specific credential directly in production:
// See https://learn.microsoft.com/javascript/api/overview/azure/identity-readme?view=azure-node-latest#credential-classes
// const credential = new ManagedIdentityCredential();

// For user-assigned managed identity
// const credential = new DefaultAzureCredential({
//   managedIdentityClientId: process.env.AZURE_POSTGRESQL_CLIENTID
// });

// Acquire access token for Azure PostgreSQL
const tokenResponse = await credential.getToken(
  "https://ossrdbms-aad.database.windows.net/.default"
);

const client = new Client({
  host: process.env.AZURE_POSTGRESQL_HOST,
  database: process.env.AZURE_POSTGRESQL_DATABASE,
  user: process.env.AZURE_POSTGRESQL_USER,  // Entra ID user
  password: tokenResponse.token,             // Token as password
  port: Number(process.env.AZURE_POSTGRESQL_PORT) || 5432,
  ssl: { rejectUnauthorized: true }
});

await client.connect();

Core Workflows

1. Single Client Connection

import { Client } from "pg";

const client = new Client({
  host: process.env.AZURE_POSTGRESQL_HOST,
  database: process.env.AZURE_POSTGRESQL_DATABASE,
  user: process.env.AZURE_POSTGRESQL_USER,
  password: process.env.AZURE_POSTGRESQL_PASSWORD,
  port: 5432,
  ssl: { rejectUnauthorized: true }
});

try {
  await client.connect();
  
  const result = await client.query("SELECT NOW() as current_time");
  console.log(result.rows[0].current_time);
} finally {
  await client.end();  // Always close connection
}

2. Connection Pool (Recommended for Production)

import { Pool } from "pg";

const pool = new Pool({
  host: process.env.AZURE_POSTGRESQL_HOST,
  database: process.env.AZURE_POSTGRESQL_DATABASE,
  user: process.env.AZURE_POSTGRESQL_USER,
  password: process.env.AZURE_POSTGRESQL_PASSWORD,
  port: 5432,
  ssl: { rejectUnauthorized: true },
  
  // Pool configuration
  max: 20,                    // Maximum connections in pool
  idleTimeoutMillis: 30000,   // Close idle connections after 30s
  connectionTimeoutMillis: 10000  // Timeout for new connections
});

// Query using pool (automatically acquires and releases connection)
const result = await pool.query("SELECT * FROM users WHERE id = $1", [userId]);

// Explicit checkout for multiple queries
const client = await pool.connect();
try {
  const res1 = await client.query("SELECT * FROM users");
  const res2 = await client.query("SELECT * FROM orders");
} finally {
  client.release();  // Return connection to pool
}

// Cleanup on shutdown
await pool.end();

3. Parameterized Queries (Prevent SQL Injection)

// ALWAYS use parameterized queries - never concatenate user input
const userId = 123;
const email = "user@example.com";

// Single parameter
const result = await pool.query(
  "SELECT * FROM users WHERE id = $1",
  [userId]
);

// Multiple parameters
const result = await pool.query(
  "INSERT INTO users (email, name, created_at) VALUES ($1, $2, NOW()) RETURNING *",
  [email, "John Doe"]
);

// Array parameter
const ids = [1, 2, 3, 4, 5];
const result = await pool.query(
  "SELECT * FROM users WHERE id = ANY($1::int[])",
  [ids]
);

4. Transactions

const client = await pool.connect();

try {
  await client.query("BEGIN");
  
  const userResult = await client.query(
    "INSERT INTO users (email) VALUES ($1) RETURNING id",
    ["user@example.com"]
  );
  const userId = userResult.rows[0].id;
  
  await client.query(
    "INSERT INTO orders (user_id, total) VALUES ($1, $2)",
    [userId, 99.99]
  );
  
  await client.query("COMMIT");
} catch (error) {
  await client.query("ROLLBACK");
  throw error;
} finally {
  client.release();
}

5. Transaction Helper Function

async function withTransaction<T>(
  pool: Pool,
  fn: (client: PoolClient) => Promise<T>
): Promise<T> {
  const client = await pool.connect();
  try {
    await client.query("BEGIN");
    const result = await fn(client);
    await client.query("COMMIT");
    return result;
  } catch (error) {
    await client.query("ROLLBACK");
    throw error;
  } finally {
    client.release();
  }
}

// Usage
const order = await withTransaction(pool, async (client) => {
  const user = await client.query(
    "INSERT INTO users (email) VALUES ($1) RETURNING *",
    ["user@example.com"]
  );
  const order = await client.query(
    "INSERT INTO orders (user_id, total) VALUES ($1, $2) RETURNING *",
    [user.rows[0].id, 99.99]
  );
  return order.rows[0];
});

6. Typed Queries with TypeScript

import { Pool, QueryResult } from "pg";

interface User {
  id: number;
  email: string;
  name: string;
  created_at: Date;
}

// Type the query result
const result: QueryResult<User> = await pool.query<User>(
  "SELECT * FROM users WHERE id = $1",
  [userId]
);

const user: User | undefined = result.rows[0];

// Type-safe insert
async function createUser(
  pool: Pool,
  email: string,
  name: string
): Promise<User> {
  const result = await pool.query<User>(
    "INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *",
    [email, name]
  );
  return result.rows[0];
}

Pool with Entra ID Token Refresh

For long-running applications, tokens expire and need refresh:

import { Pool, PoolConfig } from "pg";
import { DefaultAzureCredential, AccessToken } from "@azure/identity";

class AzurePostgresPool {
  private pool: Pool | null = null;
  private credential: DefaultAzureCredential;
  private tokenExpiry: Date | null = null;
  private config: Omit<PoolConfig, "password">;

  constructor(config: Omit<PoolConfig, "password">) {
    this.credential = new DefaultAzureCredential({requiredEnvVars: ["AZURE_TOKEN_CREDENTIALS"]});
    this.config = config;
  }

  private async getToken(): Promise<string> {
    const tokenResponse = await this.credential.getToken(
      "https://ossrdbms-aad.database.windows.net/.default"
    );
    this.tokenExpiry = new Date(tokenResponse.expiresOnTimestamp);
    return tokenResponse.token;
  }

  private isTokenExpired(): boolean {
    if (!this.tokenExpiry) return true;
    // Refresh 5 minutes before expiry
    return new Date() >= new Date(this.tokenExpiry.getTime() - 5 * 60 * 1000);
  }

  async getPool(): Promise<Pool> {
    if (this.pool && !this.isTokenExpired()) {
      return this.pool;
    }

    // Close existing pool if token expired
    if (this.pool) {
      await this.pool.end();
    }

    const token = await this.getToken();
    this.pool = new Pool({
      ...this.config,
      password: token
    });

    return this.pool;
  }

  async query<T>(text: string, params?: any[]): Promise<QueryResult<T>> {
    const pool = await this.getPool();
    return pool.query<T>(text, params);
  }

  async end(): Promise<void> {
    if (this.pool) {
      await this.pool.end();
      this.pool = null;
    }
  }
}

// Usage
const azurePool = new AzurePostgresPool({
  host: process.env.AZURE_POSTGRESQL_HOST!,
  database: process.env.AZURE_POSTGRESQL_DATABASE!,
  user: process.env.AZURE_POSTGRESQL_USER!,
  port: 5432,
  ssl: { rejectUnauthorized: true },
  max: 20
});

const result = await azurePool.query("SELECT NOW()");

Error Handling

import { DatabaseError } from "pg";

try {
  await pool.query("INSERT INTO users (email) VALUES ($1)", [email]);
} catch (error) {
  if (error instanceof DatabaseError) {
    switch (error.code) {
      case "23505":  // unique_violation
        console.error("Duplicate entry:", error.detail);
        break;
      case "23503":  // foreign_key_violation
        console.error("Foreign key constraint failed:", error.detail);
        break;
      case "42P01":  // undefined_table
        console.error("Table does not exist:", error.message);
        break;
      case "28P01":  // invalid_password
        console.error("Authentication failed");
        break;
      case "57P03":  // cannot_connect_now (server starting)
        console.error("Server unavailable, retry later");
        break;
      default:
        console.error(`PostgreSQL error ${error.code}: ${error.message}`);
    }
  }
  throw error;
}

Connection String Format

// Alternative: Use connection string
const pool = new Pool({
  connectionString: `postgres://${user}:${password}@${host}:${port}/${database}?sslmode=require`
});

// With SSL required (Azure)
const connectionString = 
  `postgres://user:password@server.postgres.database.azure.com:5432/mydb?sslmode=require`;

Pool Events

const pool = new Pool({ /* config */ });

pool.on("connect", (client) => {
  console.log("New client connected to pool");
});

pool.on("acquire", (client) => {
  console.log("Client checked out from pool");
});

pool.on("release", (err, client) => {
  console.log("Client returned to pool");
});

pool.on("remove", (client) => {
  console.log("Client removed from pool");
});

pool.on("error", (err, client) => {
  console.error("Unexpected pool error:", err);
});

Azure-Specific Configuration

SettingValueDescription
ssl.rejectUnauthorizedtrueAlways use SSL for Azure
Default port5432Standard PostgreSQL port
PgBouncer port6432Use when PgBouncer enabled
Token scopehttps://ossrdbms-aad.database.windows.net/.defaultEntra ID token scope
Token lifetime~1 hourRefresh before expiry

Pool Sizing Guidelines

WorkloadmaxidleTimeoutMillis
Light (dev/test)5-1030000
Medium (production)20-3030000
Heavy (high concurrency)50-10010000

Note: Azure PostgreSQL has connection limits based on SKU. Check your tier's max connections.

Best Practices

  1. Always use connection pools for production applications
  2. Use parameterized queries - Never concatenate user input
  3. Always close connections - Use try/finally or connection pools
  4. Enable SSL - Required for Azure (ssl: { rejectUnauthorized: true })
  5. Handle token refresh - Entra ID tokens expire after ~1 hour
  6. Set connection timeouts - Avoid hanging on network issues
  7. Use transactions - For multi-statement operations
  8. Monitor pool metrics - Track pool.totalCount, pool.idleCount, pool.waitingCount
  9. Graceful shutdown - Call pool.end() on application termination
  10. Use TypeScript generics - Type your query results for safety

Key Types

import {
  Client,
  Pool,
  PoolClient,
  PoolConfig,
  QueryResult,
  QueryResultRow,
  DatabaseError,
  QueryConfig
} from "pg";

Reference Links

ResourceURL
node-postgres Docshttps://node-postgres.com
npm Packagehttps://www.npmjs.com/package/pg
GitHub Repositoryhttps://github.com/brianc/node-postgres
Azure PostgreSQL Docshttps://learn.microsoft.com/azure/postgresql/flexible-server/
Passwordless Connectionhttps://learn.microsoft.com/azure/postgresql/flexible-server/how-to-connect-with-managed-identity

microsoft tarafından daha fazla skill

oss-growth
microsoft
OSS büyüme korsanı kişiliği
agent-framework-azure-ai-py
microsoft
Microsoft Agent Framework Python SDK'sini (agent-framework-azure-ai) kullanarak Azure AI Foundry aracıları oluşturun. AzureAIAgentsProvider ile kalıcı aracılar oluştururken, barındırılan araçları (kod yorumlayıcı, dosya arama, web araması) kullanırken, MCP sunucularını entegre ederken, konuşma iş parçacıklarını yönetirken veya akış yanıtları uygularken kullanın. Fonksiyon araçlarını, yapılandırılmış çıktıları ve çok araçlı aracıları kapsar.
development
airunway-aks-setup
microsoft
Set up AI Runway on AKS — from bare cluster to running model. Covers cluster verification, controller install, GPU assessment, provider setup, and first deployment. WHEN: "setup AI Runway", "onboard AKS cluster", "install AI Runway", "airunway setup", "deploy model to AKS", "GPU inference on AKS", "KAITO setup on AKS", "run LLM on AKS", "vLLM on AKS", "set up model serving on AKS", "AI Runway controller".
devops
appinsights-instrumentation
microsoft
Azure Application Insights ile web uygulamalarını enstrümante etme rehberi. Telemetri desenleri, SDK kurulumu ve yapılandırma referansları sağlar. NE ZAMAN: uygulama nasıl enstrümante edilir, App Insights SDK, telemetri desenleri, App Insights nedir, Application Insights rehberliği, enstrümantasyon örnekleri, APM en iyi uygulamaları.
devops
applicationinsights-web-ts
microsoft
Tarayıcı/web uygulamalarını Application Insights JavaScript SDK'sı (@microsoft/applicationinsights-web) ile izleyin. Gerçek Kullanıcı İzleme (RUM) için kullanın — sayfa görünümleri, tıklamalar, AJAX/fetch bağımlılıkları, özel durumlar, özel olaylar ve arka uç OpenTelemetry izleriyle ilişkilendirilen tarayıcı tarafı GenAI aracı izleri. SDK Loader Script ve npm kurulumunu, çerçeve uzantılarını (React, React Native, Angular), Tıklama Analitiğini, telemetri başlatıcılarını ve tarayıcıdan yayılan aracı/araç/model yayılımları için OTel GenAI anlamsal kurallarını kapsar.
devops
azure-ai-anomalydetector-java
microsoft
Azure AI Anomaly Detector SDK for Java ile anomali tespiti uygulamaları oluşturun. Tek değişkenli/çok değişkenli anomali tespiti, zaman serisi analizi veya yapay zeka destekli izleme uygularken kullanın.
development
azure-ai-language-conversations-py
microsoft
azure-ai-language-conversations Python SDK'sini kullanarak Konuşma Dili Anlama (CLU) uygulayın. ConversationAnalysisClient ile konuşma niyetini ve varlıklarını analiz etmek, NLP özellikleri oluşturmak veya dil anlamayı uygulamalara entegre etmek için kullanın.
development
azure-ai-ml-py
microsoft
Azure Machine Learning SDK v2 for Python. Makine öğrenimi çalışma alanları, işler, modeller, veri kümeleri, bilgi işlem ve iş akışları için kullanın. Tetikleyiciler: "azure-ai-ml", "MLClient", "workspace", "model registry", "training jobs", "datasets".
development