TypeORM with NestJS
Entity setup, repositories, migrations, relations, and query builder
What You’ll Build
After following this guide, you will have a working implementation of typeorm with nestjs in your project. Set up TypeORM with NestJS for a fully typed, enterprise-grade data layer. NestJS’s module system integrates cleanly with TypeORM’s repository pattern. Covers entity definitions, relations, migration generation, and the query builder for complex queries.
Use Cases & Problems Solved
- Set up a production-ready database layer with type-safe queries
- Manage schema changes through migrations without data loss
- Avoid raw SQL injection risks and inconsistent data access patterns
Prerequisites
- NestJS project
- PostgreSQL database
- TypeScript
Step-by-Step Implementation
Install TypeORM integration
The following snippet shows how to install typeorm integration. Copy this into your project and adjust the values for your environment.
npm install @nestjs/typeorm typeorm pg
Configure in AppModule
The following snippet shows how to configure in appmodule. Copy this into your project and adjust the values for your environment.
// app.module.ts
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
url: process.env.DATABASE_URL,
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: process.env.NODE_ENV !== 'production', // auto-sync in dev only!
}),
UsersModule,
],
})
export class AppModule {}
Define entity and service
The following snippet shows how to define entity and service. Copy this into your project and adjust the values for your environment.
// user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
email: string;
@Column()
name: string;
@OneToMany(() => Post, post => post.author)
posts: Post[];
}
// users.service.ts
@Injectable()
export class UsersService {
constructor(@InjectRepository(User) private usersRepo: Repository<User>) {}
findAll() { return this.usersRepo.find({ relations: ['posts'] }); }
findOne(id: number) { return this.usersRepo.findOneBy({ id }); }
create(dto: CreateUserDto) { return this.usersRepo.save(dto); }
}
⚠️ Don’t Do This
❌ Using synchronize: true in production
TypeOrmModule.forRoot({
synchronize: true, // DANGEROUS in production!
// Auto-alters tables — can DROP COLUMNS with data!
})
✅ Use migrations in production, synchronize only in development
TypeOrmModule.forRoot({
synchronize: process.env.NODE_ENV !== 'production',
migrationsRun: true, // Run pending migrations on startup
migrations: [__dirname + '/migrations/*{.ts,.js}'],
})
// Generate migrations: npx typeorm migration:generate -n AddUserPhone
Testing
Verify your implementation with these tests:
// __tests__/typeorm-with-nestjs.test.ts
import { describe, it, expect } from 'vitest';
describe('TypeORM with NestJS', () => {
it('should initialize without errors', () => {
// Test that the setup completes successfully
expect(() => setup()).not.toThrow();
});
it('should handle the primary use case', async () => {
const result = await execute();
expect(result).toBeDefined();
expect(result.success).toBe(true);
});
it('should handle edge cases', async () => {
// Test with empty/null input
const result = await execute(null);
expect(result.error).toBeDefined();
});
});
Verification
npm run start:dev
# Check NestJS logs for 'TypeORM connected' message
# Test with curl:
curl http://localhost:3000/users
# Should return [] initially, then data after POST Related Specs
Prisma + PostgreSQL Full Setup
Schema design, migrations, seeding, CRUD operations, and relations
Safe Database Migrations
Zero-downtime migration patterns, rollback strategies, and data backfills