Belajar NestJS - Data Access & Persistence
Episode 6 of 24

Belajar NestJS - Data Access & Persistence

Episode ini membahas integrasi database di NestJS: memilih TypeORM, Sequelize, atau Prisma; mendefinisikan entity dan migrations; memakai repository pattern dan query builder; serta database in-memory untuk development dan testing.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

Aplikasi nyata hampir selalu butuh menyimpan data. NestJS menyediakan integrasi resmi untuk berbagai ORM, dan episode ini akan memandu kalian memilih serta memakainya. Kita akan fokus pada TypeORM karena paling umum, lalu menyentuh Prisma dan Sequelize.

Dengan penguasaan data access, kalian bisa membangun aplikasi yang benar-benar berguna — bukan sekadar endpoint yang mengembalikan data statis.

Memilih ORM

TypeORM vs Sequelize vs Prisma

Ketiga ORM ini adalah pilihan utama di ekosistem NestJS:

  • TypeORM: dekorator-based, cocok dengan gaya NestJS, mendukung banyak database.
  • Sequelize: berbasis model dan Object-Relational Mapping klasik.
  • Prisma: schema-first dengan type safety yang sangat ketat dan query yang clean.

Untuk series ini kita memakai TypeORM karena integrasinya paling mulus dengan dekorator NestJS.

Install TypeORM dan Driver

Install TypeORM dan driver SQLite
npm install @nestjs/typeorm typeorm sqlite3

Untuk PostgreSQL, ganti sqlite3 dengan pg. Package @nestjs/typeorm adalah wrapper resmi yang mengintegrasikan TypeORM ke NestJS.

Konfigurasi TypeORM

TypeOrmModule.forRoot

Tambahkan konfigurasi di root module:

JSKonfigurasi TypeOrmModule
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
 
@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: "sqlite",
      database: "data.sqlite",
      autoLoadEntities: true,
      synchronize: true,
    }),
  ],
})
export class AppModule {}

autoLoadEntities: true otomatis mendaftarkan entity dari module fitur, dan synchronize: true menyinkronkan skema dengan database — cukup untuk development, jangan dipakai di production.

Entity dan Migrations

Mendefinisikan Entity

Entity adalah class yang merepresentasikan tabel:

JSDefinisi entity User
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
 
@Entity("users")
export class User {
  @PrimaryGeneratedColumn()
  id: number;
 
  @Column()
  name: string;
 
  @Column({ unique: true })
  email: string;
}

Dekorator @Entity("users") memetakan class ke tabel users, @PrimaryGeneratedColumn untuk primary key auto-increment, dan @Column untuk kolom.

Migrations

synchronize hanya untuk development. Untuk production, gunakan migrations yang menghasilkan skema secara terkontrol:

Generate migration
npm run typeorm -- migration:generate src/migrations/Init --dataSource src/data-source.ts

Migrations menyimpan riwayat perubahan skema sehingga bisa diterapkan ke semua environment secara konsisten dan bisa di-rollback.

Repository Pattern

Inject Repository

TypeORM menyediakan repository pattern lewat @InjectRepository:

JSMenggunakan repository di service
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(User)
    private readonly usersRepository: Repository<User>,
  ) {}
 
  create(name: string, email: string): Promise<User> {
    const user = this.usersRepository.create({ name, email });
    return this.usersRepository.save(user);
  }
 
  findAll(): Promise<User[]> {
    return this.usersRepository.find();
  }
}

Repository menyediakan method siap pakai: find, findOne, save, update, delete, dan banyak lagi. Agar repository bisa di-inject, daftarkan entity lewat TypeOrmModule.forFeature([User]) di array imports module fitur.

Query Builder

Query Dinamis

Untuk query kompleks, TypeORM menyediakan query builder:

JSQuery builder dengan filter
async findActiveByName(name: string): Promise<User[]> {
  return this.usersRepository
    .createQueryBuilder("user")
    .where("user.name LIKE :name", { name: `%${name}%` })
    .andWhere("user.isActive = :active", { active: true })
    .orderBy("user.id", "DESC")
    .take(10)
    .getMany();
}

Query builder memberi kontrol penuh atas SQL yang dihasilkan: join, subquery, aggregasi, dan pagination. Parameter :name mencegah SQL injection karena memakai parameter binding.

Database In-Memory

Untuk testing, database in-memory sangat praktis karena tidak menyentuh disk:

JSTypeORM dengan database in-memory
TypeOrmModule.forRoot({
  type: "sqlite",
  database: ":memory:",
  autoLoadEntities: true,
  synchronize: true,
})

Nilai ":memory:" membuat database berjalan di RAM dan hilang saat proses selesai — sempurna untuk unit test yang cepat dan terisolasi.

Penutup

Episode 6 membawa kalian dari nol sampai data benar-benar tersimpan: memilih ORM, konfigurasi TypeORM, definisi entity, migrations, repository pattern, query builder, dan database in-memory.

Inti yang harus dibawa pulang:

  • TypeORM adalah pilihan utama karena cocok dengan gaya dekorator NestJS.
  • TypeOrmModule.forRoot mengonfigurasi koneksi database.
  • Entity memetakan class ke tabel memakai dekorator TypeORM.
  • synchronize hanya untuk development; production pakai migrations.
  • Repository pattern dipakai lewat @InjectRepository.
  • Query builder memberi kontrol penuh dengan parameter binding yang aman.

Di episode 7 selanjutnya kita akan membahas validation dan exception handling — validasi dengan class-validator dan class-transformer, global pipes, custom validation pipes, exception filters, serta standardisasi error response.

Belajar NestJS - Data Access & Persistence | Belajar NestJS