Resource Management ("using")
postgrejs objects that hold onto a server-side resource — a socket, a portal, a prepared statement — implement the
TC39 Explicit Resource Management proposal, using
its await using syntax to close themselves automatically when the enclosing block exits.
Manual try/finally vs. using
Without it, every resource has to be closed by hand, and it is easy to forget the finally when a code path grows:
const connection = new Connection({ host: 'localhost', database: 'my_db' });
await connection.connect();
try {
const result = await connection.query('select 1');
console.log(result.rows);
} finally {
await connection.close();
}
With await using, the same guarantee comes for free — the object is disposed as soon as control leaves the block,
including when it leaves because of a thrown error:
{
await using connection = new Connection({ host: 'localhost', database: 'my_db' });
await connection.connect();
const result = await connection.query('select 1');
console.log(result.rows);
} // connection.close() is called here automatically
If the code inside the block throws, connection.close() still runs before the error propagates — there is no
separate catch/finally to write.
What Implements It
Symbol.asyncDispose (which calls close()) is currently implemented by:
await using connection = new Connection({ host: 'localhost', database: 'my_db' });
await connection.connect();
await using statement = await connection.prepare('select * from users where id = $1');
const result = await statement.execute({ params: [1] });
console.log(result.rows);
// statement.close() runs first, then connection.close(), in reverse declaration order
LargeObject and LogicalReplication do not implement Symbol.asyncDispose as of this version — close them
explicitly with try/finally (see Large Objects and
Logical Replication).
await using also composes with Pool-acquired connections: since connection.close() on a pooled connection
releases it back to the pool rather than closing the socket (see Connection Pooling),
the same pattern works unchanged:
{
await using connection = await pool.acquire();
const result = await connection.query('select 1');
console.log(result.rows);
} // released back to the pool automatically
Requirements
using/await using needs TypeScript 5.2 or later to compile, targeting a runtime with Symbol.asyncDispose
available. postgrejs polyfills Symbol.asyncDispose itself if the runtime doesn't provide it natively, so the
pattern works across supported Node versions (node >= 20.x) without any extra setup.