eslint-plugin-pgbadpatterns
v0.1.0
Published
ESLint rules that catch PostgreSQL transaction & connection-pooling anti-patterns: I/O inside transactions, session-state behind a transaction pooler, and pass-through transactions.
Maintainers
Readme
eslint-plugin-pgbadpatterns
ESLint rules that catch PostgreSQL transaction & connection-pooling anti-patterns — the code
shapes that cause idle-in-transaction pool exhaustion and transaction-pooler (RDS Proxy / pgBouncer)
breakage under load. Part of pgbadpatterns; the rules are
validated against a real incident corpus (see the repo's docs/validation.md).
Scope: v1 covers transaction hygiene and connection-pooling safety — not query-speed/index tuning.
Install
npm install --save-dev eslint-plugin-pgbadpatternsRequires ESLint 9+.
Usage (flat config — eslint.config.js)
import pgbadpatterns from 'eslint-plugin-pgbadpatterns';
export default [
{
plugins: { pgbadpatterns },
rules: {
'pgbadpatterns/no-io-in-transaction': 'error',
'pgbadpatterns/no-session-state-on-pooled-conn': 'warn',
'pgbadpatterns/no-passthrough-transaction': 'error',
},
},
];Usage (legacy .eslintrc.*)
module.exports = {
plugins: ['pgbadpatterns'],
rules: {
'pgbadpatterns/no-io-in-transaction': 'error',
'pgbadpatterns/no-session-state-on-pooled-conn': 'warn',
'pgbadpatterns/no-passthrough-transaction': 'error',
},
};Rules
| Rule | What it flags |
| --- | --- |
| no-io-in-transaction | An awaited network/IO call (a payment SDK, mailer, HTTP client…) inside a transaction callback — holds the pooled connection idle in transaction until the call returns. |
| no-session-state-on-pooled-conn | Session-scoped SQL (SET …, pg_advisory_lock(...)) that breaks or pins a connection behind a transaction pooler. |
| no-passthrough-transaction | A withTransaction(fn, em) call that passes an existing manager, so the callback joins the caller's transaction instead of opening its own. |
Type-aware rule
no-passthrough-transaction is type-aware: it needs typed linting to resolve the argument type.
Configure @typescript-eslint/parser with type information (projectService: true or
parserOptions.project) for it to fire. The other two rules work without type information.
License
MIT — see LICENSE.
