DataSource setup
src/data-source.ts:
poolSize: 10 keeps your app’s connection share at half of PgBouncer’s default_pool_size = 20, leaving room for migrations and other workloads.
If you’re using pg directly (TypeORM’s default for type: "postgres"), prepared statements aren’t enabled unless you call client.query() with the name option, which TypeORM’s repository methods don’t do. So unlike Prisma and Drizzle, no explicit prepare=false flag is needed. Just don’t switch to a driver that does auto-prepare.
Entities
src/entities/User.ts:
src/entities/Post.ts:
{ name: "users" } / { name: "created_at" } overrides map the TypeScript names to snake_case SQL. Match whatever convention you’ve set for the rest of your schema.
Queries via repositories
Migrations
TypeORM has its own migration runner. Generate from current schema vs entities:src/migrations/ as TypeScript classes implementing MigrationInterface. As with Drizzle, the generated migration is largely SQL, so it’s easy to inspect before applying.
TypeORM’s tracking table is migrations. Don’t touch it.
One autogenerate caveat is worth knowing: TypeORM compares your entities against the live database schema, so you need a development database that matches your production schema for autogenerate to produce a clean diff. Most teams keep a local Postgres pinned to production’s schema for this.
RLS from TypeORM
supabase_admin connection, bypasses RLS. For RLS-respecting queries, the same transaction-with-SET-LOCAL pattern as Prisma and Drizzle:
tx.query calls here are the raw-SQL escape hatch on the transactional connection.
TypeORM in NestJS
In a NestJS project, the standard wiring isTypeOrmModule.forRoot() in your app module:
Next steps
Connection pooling
The PgBouncer constraints
poolSize: 10 and disabled-prepares work around.Migrations
TypeORM’s runner in the context of the other ORMs.
Direct Postgres
For SQL TypeORM doesn’t express: bulk imports, schema introspection.
Prisma
The TypeScript ORM most teams default to today.