2026'da NestJS ve TypeORM: Migration'lar, İlişkiler ve Mülakat Soruları
TypeORM 1.1 migration'ları, entity ilişkileri, repository pattern'leri ve backend geliştiriciler için yaygın mülakat sorularıyla NestJS TypeORM entegrasyonunda ustalaşın.

NestJS TypeORM, kurumsal Node.js backend'leri için en iyi test edilmiş ORM entegrasyonlarından biri olmaya devam ediyor. TypeORM'un Mayıs 2026'da 1.0 sürümüne ulaşması, ardından bağlantı yönetimi ve ilişki kalıcılığını düzelten 1.1.x yama serisi ve NestJS 12'nin ESM geçişini tamamlamasıyla, bu stack üretim uygulamaları için olgun ve kararlı bir temel haline geldi. Bu rehber, her backend geliştiricinin ustalaşması gereken temel kalıpları kapsıyor: migration'lar, entity ilişkileri, repository pattern ve bunlarla ilgili mülakat soruları.
NestJS 12, temel paketleri ESM olarak sunuyor ve Node.js 20.19+ veya 22.12+ gerektiriyor. @nestjs/typeorm v12 paketi de aynı modeli takip ediyor. TypeORM 1.1.2, DataSource.initialize() içindeki bağlantı sızıntılarını düzeltiyor ve ilişkiler yüklenmediğinde many-to-many junction satır kalıcılığını düzeltiyor.
NestJS 12'de TypeORM Migration'larını Yapılandırma
Üretim veritabanları için ilk kural: asla synchronize: true kullanmamak. Auto-sync, entity metadata'sını canlı şemayla karşılaştırır ve değişiklikleri doğrudan uygular; bu da sütun silme, tip değişikliği veya alan yeniden adlandırma durumlarında veri kaybı riski taşır. Migration'lar sürümlenmiş, incelenebilir ve geri alınabilir bir alternatif sunar.
TypeORM 1.x, CLI için NestJS modül yapılandırmasından ayrı, özel bir DataSource yapılandırma dosyası gerektirir. CLI, NestJS bağımlılık enjeksiyonunu çözemediğinden bağımsız bir giriş noktasına ihtiyaç duyar.
import { DataSource } from 'typeorm';
import { config } from 'dotenv';
config(); // Load .env variables
export default new DataSource({
type: 'postgres',
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT || '5432'),
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
entities: ['src/**/*.entity.ts'],
migrations: ['src/migrations/*.ts'],
synchronize: false,
});NestJS modül yapılandırması bu ayarları yansıtır ancak bağımlılık enjeksiyonlu TypeOrmModule.forRootAsync pattern'ini kullanır:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
type: 'postgres',
host: config.get('DB_HOST'),
port: config.getOrThrow<number>('DB_PORT'),
username: config.get('DB_USER'),
password: config.get('DB_PASSWORD'),
database: config.get('DB_NAME'),
autoLoadEntities: true, // Auto-register entities from feature modules
synchronize: false, // Always false in production
}),
}),
],
})
export class AppModule {}autoLoadEntities: true, feature modüllerinde TypeOrmModule.forFeature() ile import edilen her entity'yi otomatik olarak kaydederek manuel entities dizisinin yerini alır.
Migration İş Akışı: Oluştur, İncele, Çalıştır
TypeORM 1.x, eski ts-node ./node_modules/typeorm/cli yaklaşımının yerini alan typeorm-ts-node-commonjs'i önerilen CLI runner olarak sunar. Bu script'leri package.json'a ekleyin:
{
"migration:generate": "typeorm-ts-node-commonjs migration:generate src/migrations/$npm_config_name -d src/config/typeorm.config.ts",
"migration:run": "typeorm-ts-node-commonjs migration:run -d src/config/typeorm.config.ts",
"migration:revert": "typeorm-ts-node-commonjs migration:revert -d src/config/typeorm.config.ts"
}generate komutu entity metadata'sını canlı veritabanıyla karşılaştırır ve SQL ifadeleri üretir. Çıktıyı commit etmeden önce her zaman inceleyin. TypeORM sütun ekleme, silme, tip değişiklikleri, indeks değişiklikleri ve foreign key değişikliklerini algılar, ancak veri backfill'lerini, tablo yeniden adlandırmalarını (drop ve create olarak görünür) ve veritabanı uzantıları veya trigger'larla ilgili herhangi bir şeyi kaçırır.
Yeniden adlandırılan bir sütun, ALTER RENAME yerine DROP + ADD üretir. Bu mevcut verileri yok eder. up() metodundaki SQL'i her zaman inceleyin ve gerektiğinde manuel olarak düzeltin.
Entity İlişkileri: OneToMany, ManyToOne, ManyToMany
TypeORM entity ilişkileri, decorator'lar kullanarak doğrudan SQL foreign key'lerine eşlenir. Üç temel ilişki türünü ve seçeneklerini anlamak, her NestJS veritabanı modülü için temeldir.
Birden fazla Order kaydına sahip bir User en yaygın pattern'i gösterir:
import { Entity, PrimaryGeneratedColumn, Column, OneToMany, CreateDateColumn } from 'typeorm';
import { Order } from './order.entity';
@Entity('users')
export class User {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column({ unique: true })
email: string;
@Column()
name: string;
@OneToMany(() => Order, (order) => order.user)
orders: Order[]; // No DB column created here; relation lives on the Order side
@CreateDateColumn()
createdAt: Date;
}import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
import { User } from './user.entity';
@Entity('orders')
export class Order {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column('decimal', { precision: 10, scale: 2 })
total: number;
@Column({ default: 'pending' })
status: string;
@ManyToOne(() => User, (user) => user.orders, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'user_id' }) // Explicit FK column name
user: User;
}@ManyToOne tarafı foreign key'in sahibidir. @JoinColumn, @ManyToOne için isteğe bağlıdır (TypeORM çıkarır), ancak açık isimlendirme raw query'lerde veya migration diff'lerinde sürprizleri önler.
Many-to-many ilişkiler için TypeORM otomatik olarak bir junction tablo oluşturur:
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from 'typeorm';
import { Category } from './category.entity';
@Entity('products')
export class Product {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column('decimal', { precision: 10, scale: 2 })
price: number;
@ManyToMany(() => Category, (category) => category.products)
@JoinTable({ name: 'product_categories' }) // Owns the junction table
categories: Category[];
}@JoinTable ilişkinin tam olarak bir tarafında görünmelidir. Hangi entity'nin junction tablosuna sahip olduğunu tanımlar ve ismini kontrol eder.
Node.js / NestJS mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
Repository Pattern ve Custom Repository'ler
NestJS modül ve DI sistemi, TypeORM repository'lerini TypeOrmModule.forFeature() aracılığıyla entegre eder. Varsayılan Repository<T>'yi enjekte etmek standart CRUD işlemlerini kapsar. Sorgular karmaşıklaştığında, custom repository'ler bu mantığı kapsüller.
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Order } from '../entities/order.entity';
import { OrdersService } from './orders.service';
import { OrdersController } from './orders.controller';
@Module({
imports: [TypeOrmModule.forFeature([Order])],
providers: [OrdersService],
controllers: [OrdersController],
})
export class OrdersModule {}import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Order } from '../entities/order.entity';
@Injectable()
export class OrdersService {
constructor(
@InjectRepository(Order)
private readonly orderRepo: Repository<Order>,
) {}
async findByUser(userId: string): Promise<Order[]> {
return this.orderRepo.find({
where: { user: { id: userId } },
relations: ['user'], // Eager-load the user relation
order: { createdAt: 'DESC' }, // Most recent first
});
}
async findWithFilters(status: string, minTotal: number): Promise<Order[]> {
// QueryBuilder for complex queries
return this.orderRepo
.createQueryBuilder('order')
.leftJoinAndSelect('order.user', 'user')
.where('order.status = :status', { status })
.andWhere('order.total >= :minTotal', { minTotal })
.orderBy('order.total', 'DESC')
.getMany();
}
}find() API'si basit sorguları yönetir. QueryBuilder join'leri, alt sorguları, aggregation'ları ve hassas SQL kontrolü gerektiren her şeyi yönetir. Her ikisini de aynı servis içinde kullanmak tamamen geçerlidir: basit aramalar için find(), sorgu seçenekler API'si ile ifade edilemediğinde QueryBuilder kullanın.
Veri Bütünlüğü için Transaction Yönetimi
Birden fazla tabloyu değiştiren işlemler transaction gerektirir. TypeORM iki yaklaşım sunar: DataSource.transaction() metodu ve QueryRunner API.
async createOrderWithItems(
userId: string,
items: { productId: string; quantity: number }[],
dataSource: DataSource,
): Promise<Order> {
return dataSource.transaction(async (manager) => {
// All operations use the transactional manager
const order = manager.create(Order, {
user: { id: userId },
total: 0,
status: 'pending',
});
const savedOrder = await manager.save(order);
let total = 0;
for (const item of items) {
const product = await manager.findOneByOrFail(Product, { id: item.productId });
total += product.price * item.quantity;
await manager.save(OrderItem, {
order: savedOrder,
product,
quantity: item.quantity,
unitPrice: product.price,
});
}
savedOrder.total = total;
return manager.save(savedOrder);
});
}Callback tabanlı transaction() metodu başarıda otomatik olarak commit eder ve herhangi bir hata fırlatıldığında rollback yapar. Callback içindeki her veritabanı işlemi, enjekte edilen repository yerine sağlanan manager'ı kullanmalıdır; aksi takdirde bu işlemler transaction dışında çalışır.
Basit çok adımlı işlemler için DataSource.transaction() kullanın. Commit/rollback noktaları veya savepoint'ler üzerinde manuel kontrol gerektiğinde, örneğin toplu işlemede kısmi rollback'ler için QueryRunner'a geçin.
Yaygın NestJS TypeORM Mülakat Soruları
Bu sorular backend geliştirici mülakatlarında sıkça karşımıza çıkar. Her yanıt, senior seviye teknik tartışmada beklenen derinliği hedefler.
synchronize: true neden üretimde asla kullanılmamalıdır?
Auto-sync, onay olmadan yıkıcı şema değişikliklerini uygular. Bir sütunu silmek, bir tipi değiştirmek veya bir indeksi kaldırmak canlı verilere anında uygulanır. Migration'lar sürüm kontrolü, kod inceleme ve rollback yeteneği sağlar. synchronize'ın tek güvenli kullanımı atılabilir verilerle yerel geliştirmedir.
eager ve lazy ilişkiler arasındaki fark nedir?
Eager ilişkiler parent entity üzerindeki her sorguyla otomatik olarak yüklenir. Lazy ilişkiler bir Promise döndürür ve yalnızca erişildiğinde ayrı bir sorgu çalıştırır. Eager loading, ilişkili veriler gerekmediğinde N+1 tarzı overhead'e neden olur. Lazy loading maliyeti erteler ancak çağrı yığınının derinliklerinde beklenmeyen sorgular tetikleyebilir. find()'daki açık relations seçeneği veya QueryBuilder'daki leftJoinAndSelect, sorgu başına neyin yükleneceği üzerinde tam kontrol sağlar.
TypeORM ilişkilerinde cascade nasıl çalışır?
Bir ilişkide cascade: true ayarlamak, parent entity'yi kaydetmenin kaydedilmemiş child entity'leri de kaydetmesi anlamına gelir. cascade: ['insert', 'update'] davranışı belirli işlemlerle sınırlar. Cascade'ler veritabanı seviyesinde değil ORM seviyesinde çalışır. Veritabanı seviyesinde cascade silme için @ManyToOne decorator'ında onDelete: 'CASCADE' kullanın; bu migration'da ON DELETE CASCADE constraint'i oluşturur.
Custom repository, varsayılan Repository<T> yerine ne zaman kullanılmalıdır?
Custom repository'ler servislere ait olmayan karmaşık sorgu mantığını kapsüller. Custom repository çıkarılması gerektiğinin işaretleri: aynı QueryBuilder zinciri birden fazla serviste görünüyor, sorgu birden fazla join veya alt sorgu içeriyor, veya sorgu raw SQL gerektiriyor. Basit find() çağrıları custom repository'yi haklı çıkarmaz.
Daha fazla NestJS mimari sorusu için, NestJS guards ve interceptors rehberine bakın.
Node.js / NestJS mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
Kaynaklar
- TypeORM 1.0.0 Sürümü - ECMAScript 2023 gereksinimi, Connection kaldırma, daha katı doğrulama varsayılanları
- TypeORM 1.1.2 Sürümü - DataSource.initialize()'da bağlantı sızıntısı düzeltmesi, many-to-many junction satır düzeltmeleri
- NestJS 12 Sürümü - ESM geçişi, Node.js 20.19+/22.12+ gereksinimi
- @nestjs/typeorm 12.0.0 - Native ES modülleri, Node require(esm) ile CommonJS uyumluluğu
NestJS TypeORM Üretim Uygulamaları için Temel Çıkarımlar
- TypeORM CLI için NestJS modül yapılandırmasından bağımsız, ayrı bir
DataSourceyapılandırma dosyası kullanın - Üretim ortamlarında asla
synchronizeetkinleştirmeyin; tüm şema değişiklikleri için oluşturulan ve incelenen migration'lara güvenin @ManyToOne'ı foreign key'e sahip entity'ye yerleştirin ve raw query'lerde ve migration çıktısında netlik için açık@JoinColumnisimlendirmesi kullanın- Basit sorgular için
find()seçenekler API'si ile karmaşık join'ler, aggregation'lar ve koşullu mantık içinQueryBuilderarasında seçim yapın - Çoklu tablo mutasyonlarını
DataSource.transaction()kullanarak transaction'lara sarın ve callback içindeki her işlemin transactionalmanager'ı kullandığından emin olun - TypeORM 1.1.x'in API yüzeyini stabilize etmesi ve NestJS 12'nin ESM geçişini tamamlamasıyla, bu stack yapılandırılmış, tip güvenli veritabanı erişimi gerektiren kurumsal backend'ler için güçlü bir seçenek olmaya devam ediyor
Pratik yapmaya başla!
Mülakat simülatörleri ve teknik testlerle bilgini test et.
Node.js / NestJS kodundaki hatayı bulabilir misin?
Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Yazan:
Anthony Fillion-MailletSharpSkill kurucusu
10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.
21 Ekim 2026 tarihinde güncellendi
Etiketler
Paylaş
İlgili makaleler

NestJS + Prisma: Node.js için modern backend yığını
NestJS ve Prisma ile modern bir backend API'si oluşturmak için kapsamlı rehber. Kurulum, modeller, servisler, transaction'lar ve en iyi uygulamalar.

NestJS: Eksiksiz bir REST API Oluşturma
NestJS ile profesyonel bir REST API oluşturmak için kapsamlı rehber. Controller, Service, Module yapıları, class-validator ile doğrulama ve hata yönetimi pratik örneklerle açıklanmaktadır.

2026'da NestJS ve GraphQL: Şemalar, Resolver'lar ve Mülakat Soruları
NestJS GraphQL entegrasyonu hakkında kapsamlı rehber: schema-first ve code-first yaklaşımları, resolver'lar, DataLoader ve 2026 mülakat soruları.