Как интегрировать TypeORM с NestJS?

MiddleNestJS · Backend·Обновлено 22 июля 2026
Коротко
TypeORM интегрируется в NestJS через пакет @nestjs/typeorm: нужно импортировать TypeOrmModule.forRoot() в корневой модуль с настройками подключения и TypeOrmModule.forFeature() в feature-модулях для регистрации сущностей.

Интеграция TypeORM с NestJS

NestJS предоставляет официальный пакет @nestjs/typeorm, который оборачивает TypeORM и встраивает его в систему модулей и внедрения зависимостей фреймворка.

Установка

npm install @nestjs/typeorm typeorm pg

Подключение в корневом модуле

В AppModule вызывается TypeOrmModule.forRoot() — это настраивает единственное соединение с базой данных и делает его доступным через DI-контейнер во всём приложении.

// app.module.ts
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: process.env.DB_HOST,
      port: Number(process.env.DB_PORT),
      username: process.env.DB_USER,
      password: process.env.DB_PASS,
      database: process.env.DB_NAME,
      autoLoadEntities: true, // автоматически подхватывает сущности, зарегистрированные через forFeature
      synchronize: false,     // никогда не включать в production
    }),
  ],
})
export class AppModule {}

Объявление сущности

// user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm';

@Entity('users')
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @Column()
  name: string;

  @CreateDateColumn()
  createdAt: Date;
}

Регистрация сущности в feature-модуле

// users.module.ts
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  providers: [UsersService],
  controllers: [UsersController],
})
export class UsersModule {}

Внедрение репозитория в сервис

// users.service.ts
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {}

  findAll(): Promise<User[]> {
    return this.userRepository.find();
  }

  findOne(id: number): Promise<User | null> {
    return this.userRepository.findOneBy({ id });
  }

  async create(dto: CreateUserDto): Promise<User> {
    const user = this.userRepository.create(dto);
    return this.userRepository.save(user);
  }
}

Асинхронная конфигурация через ConfigService

Для продакшн-приложений конфигурацию принято загружать асинхронно:

TypeOrmModule.forRootAsync({
  imports: [ConfigModule],
  useFactory: (config: ConfigService) => ({
    type: 'postgres',
    host: config.get('DB_HOST'),
    port: config.get<number>('DB_PORT'),
    username: config.get('DB_USER'),
    password: config.get('DB_PASS'),
    database: config.get('DB_NAME'),
    autoLoadEntities: true,
    synchronize: false,
  }),
  inject: [ConfigService],
}),

Миграции

Вместо synchronize: true в production используют миграции TypeORM. Для этого создаётся отдельный data-source.ts с настройками, и CLI TypeORM запускается как typeorm migration:run.

Что хочет услышать интервьюер

Знание разницы между TypeOrmModule.forRoot() и TypeOrmModule.forFeature() и понимание, зачем нужны оба

Умение правильно внедрять репозиторий через @InjectRepository() с дженериком сущности

Понимание опасности synchronize: true и использование миграций в production

Знание autoLoadEntities как удобной альтернативы ручному перечислению entities[]

Способность настраивать асинхронную конфигурацию через forRootAsync и ConfigService

Пример: Асинхронная конфигурация TypeORM через ConfigService

// app.module.ts — корневое подключение
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: (config: ConfigService) => ({
        type: 'postgres',
        host: config.get('DB_HOST'),
        port: config.get<number>('DB_PORT'),
        username: config.get('DB_USER'),
        password: config.get('DB_PASS'),
        database: config.get('DB_NAME'),
        autoLoadEntities: true,
        synchronize: false,
      }),
      inject: [ConfigService],
    }),
  ],
})
export class AppModule {}

Пример: Сущность User

// user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm';

@Entity('users')
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true })
  email: string;

  @Column()
  name: string;

  @CreateDateColumn()
  createdAt: Date;
}

Пример: Feature-модуль с регистрацией сущности

// users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';

@Module({
  imports: [TypeOrmModule.forFeature([User])], // регистрация репозитория в DI-контейнере
  providers: [UsersService],
  controllers: [UsersController],
  exports: [UsersService],
})
export class UsersModule {}

Пример: Сервис с внедрённым репозиторием

// users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UsersService {
  constructor(
    // @InjectRepository обязателен — без него DI не найдёт токен репозитория
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {}

  findAll(): Promise<User[]> {
    return this.userRepository.find();
  }

  findOne(id: number): Promise<User | null> {
    return this.userRepository.findOneBy({ id });
  }

  async create(data: Partial<User>): Promise<User> {
    const user = this.userRepository.create(data);
    return this.userRepository.save(user);
  }

  async remove(id: number): Promise<void> {
    await this.userRepository.delete(id);
  }
}

Типичные ошибки

Оставляют synchronize: true в production, что может привести к потере данных при деплое

Регистрируют сущность только в forRoot entities[], но забывают добавить в forFeature() нужного модуля

Внедряют Repository<User> без декоратора @InjectRepository() — DI-контейнер не может разрешить зависимость

Не используют autoLoadEntities и вручную дублируют массив entities в нескольких местах, забывая обновлять его

Смешивают конфигурацию базы данных прямо в коде вместо вынесения в переменные окружения через ConfigService

Лучшие курсы по теме

изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Node.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее