AWS Lambda
Tested with: Lambda Node.js 22 runtime · AWS SDK v3 · Secrets Manager · PostgreSQL 17
-
Store the credential in Secrets Manager and grant the function’s role
secretsmanager:GetSecretValueon it. Read it once per container, not per invocation.src/db.ts import { GetSecretValueCommand, SecretsManagerClient } from "@aws-sdk/client-secrets-manager";import { Pool } from "pg";let pool: Pool | undefined;export async function getPool() {if (pool) return pool;const sm = new SecretsManagerClient({});const { SecretString } = await sm.send(new GetSecretValueCommand({ SecretId: "databasezy/pg-prod" }));const s = JSON.parse(SecretString!);pool = new Pool({host: `${s.host.replace(".us-east", "-pool.us-east")}`, // pooled endpointport: Number(s.port),user: s.username,password: s.password,database: s.database,ssl: { rejectUnauthorized: true, servername: s.host },max: 2,});return pool;} -
Give the function a fixed egress address. Attach it to private subnets whose route to the internet goes through a NAT gateway with an Elastic IP, and allow that IP.
shell zb api PUT /v1/orgs/{org}/instances/pg-7f3k/network -d '{"allow_cidrs": ["52.0.0.10/32"]}' # replaces the listFunctions outside a VPC use AWS’s shared, changing addresses; that requires
0.0.0.0/0on the allow-list. -
Use the pooled endpoint (transaction mode) so concurrent invocations do not exhaust
max_connections, and keepmaxper container tiny. Setcontext.callbackWaitsForEmptyEventLoop = falseif you keep the pool open.
Migrations
Section titled “Migrations”Run them from CI or from a one-off Lambda invoked in the deploy pipeline, against the direct endpoint.