nestjs-typeorm-integration について
NestJSアプリケーションへのTypeORM統合を支援するスキルです。データベース設定、エンティティ、マイグレーション、リポジトリ注入、トランザクションを扱い、既存の構成に沿ってDB対応サービスを構築・改修する開発者を対象とします。
主な機能
- 01NestJS向けTypeORM設定
- 02エンティティとリレーション設計
- 03マイグレーションによるスキーマ変更
- 04Nest DIによるリポジトリ注入
- 05トランザクションとクエリのガイド
活用シーン
- 01NestJS APIをデータベースに接続
- 02エンティティ、リレーション、マイグレーションを追加
- 03手動のリポジトリや接続処理を改修
- 04トランザクション処理を実装
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vong3432/ vibemark --skill nestjs-typeorm-integrationインストール後、Claude Code で/nestjs-typeorm-integrationを入力して読み込まれたか確認します。
詳細
NestJS + TypeORM 統合スキル
目的
このスキルは、TypeORM と NestJS をクリーンでスケーラブル、かつ本番環境に適した方法で統合するための専門アシスタントです。
このスキルは、次の用途に使用します。
- NestJS プロジェクトで TypeORM をセットアップする(データソース、モジュール、設定)
- エンティティとそのリレーションを定義またはリファクタリングする
- マイグレーションと環境ごとの DB 設定を構成する
- Nest の DI を使ってリポジトリをサービスに接続する
- トランザクションとクエリパターンを安全に実装する
- 構造レベルで DB の使用を最適化する(インデックス、クエリパターン、リレーションの読み込み)
次の用途には、このスキルを使用しないでください。
- 一般的な NestJS のモジュール/サービス/コントローラーのひな形作成 →
nestjs-project-scaffold/nestjs-modules-services-controllersを使用してください - 認証ロジック →
nestjs-authenticationを使用してください - Supabase 固有のフロー → Supabase スキルを使用してください(ただし、Supabase Postgres に TypeORM 経由で通常の DB としてアクセスする場合を除きます)
CLAUDE.md が存在する場合は、データベースの選択、命名規則、ディレクトリ構成に関するルールに従ってください。
このスキルを適用するタイミング
ユーザーから次のような依頼があった場合、このスキルを適用します。
- 「この NestJS API に TypeORM をセットアップしてください。」
- 「NestJS + TypeORM で、これらのテーブルのエンティティとマイグレーションを作成してください。」
- 「Nest のサービスにリポジトリを接続してください。」
- 「NestJS の TypeORM 設定を修正またはリファクタリングしてください。」
- 「これらのエンティティ間にリレーションを追加し、サービスロジックを更新してください。」
- 「複数ステップのこの処理でトランザクションを扱ってください。」
次の場合は、このスキルの使用を避けてください。
- DB に影響せず、高レベルの REST API コントラクトのみを変更する場合
- インメモリだけで完結するロジックを実装する場合
前提とデフォルト
プロジェクトで別途指定がない限り、次のように想定します。
- データベース:Postgres(MySQL、SQLite などにも適宜対応できます)
- TypeORM のバージョン:NestJS で現在安定しているバージョン
- 接続は Nest の
TypeOrmModule経由で構成されている - 設定は
@nestjs/configと.envファイルを通じて環境変数で管理する - エンティティは、プロジェクトのスタイルに応じて
src/modules/<feature>/entitiesまたはsrc/entitiesに配置する - マイグレーションは
src/migrationsまたはmigrationsディレクトリに配置する
高レベルアーキテクチャ
推奨される構成(必要に応じて調整してください):
project-root/
src/
config/
database.config.ts
modules/
user/
user.module.ts
user.service.ts
user.controller.ts
entities/
user.entity.ts
post/
post.module.ts
post.service.ts
post.controller.ts
entities/
post.entity.ts
infrastructure/
database/
ormconfig.ts or data-source.ts (optional central place)
migrations/
1710000000000-CreateUserTable.ts
1710000001000-CreatePostTable.ts
このスキルでは、プロジェクトが新規作成でない限り、まったく新しい構成を強制するのではなく、既存の構成に沿うようにしてください。
ステップごとのワークフロー
このスキルが有効な場合は、次の手順に従ってください。
1. TypeORM モジュールの設定
TypeORM がまだ設定されていない場合:
- 選択したデータベース用の TypeORM と DB ドライバーをインストールします。
AppModuleまたは専用のDatabaseModuleでTypeOrmModuleを設定します。
@nestjs/config を使用する例:
// src/config/database.config.ts
import { registerAs } from "@nestjs/config";
export default registerAs("database", () => ({
type: "postgres",
host: process.env.DB_HOST ?? "localhost",
port: parseInt(process.env.DB_PORT ?? "5432", 10),
username: process.env.DB_USERNAME ?? "postgres",
password: process.env.DB_PASSWORD ?? "postgres",
database: process.env.DB_NAME ?? "app_db",
}));
// src/app.module.ts
import { Module } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import databaseConfig from "./config/database.config";
import { TypeOrmModule } from "@nestjs/typeorm";
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
load: [databaseConfig],
}),
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => {
const db = config.get("database");
return {
...db,
autoLoadEntities: true,
synchronize: false, // prefer migrations in production
};
},
}),
// feature modules...
],
})
export class AppModule {}
主なルール:
- すべての開発環境以外では
synchronize: falseにします(このスキルではマイグレーションを推奨します)。 - 多くのアプリでは
autoLoadEntities: trueを使用できます。より厳密に制御する場合は、エンティティを明示的に列挙してください。
2. 環境変数
.env(および .env.example)に次の項目が含まれていることを確認します。
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=postgres
DB_NAME=app_db
このスキルでは、シークレットをコード内に置かず、環境変数や設定だけで管理できるようにします。
3. エンティティの設計
機能ごとにエンティティクラスを作成します。
// src/modules/user/entities/user.entity.ts
import {
Column,
CreateDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from "typeorm";
@Entity({ name: "users" })
export class User {
@PrimaryGeneratedColumn("uuid")
id!: string;
@Column({ unique: true })
email!: string;
@Column()
passwordHash!: string;
@Column({ default: true })
isActive!: boolean;
@CreateDateColumn()
createdAt!: Date;
@UpdateDateColumn()
updatedAt!: Date;
}
リレーションの例:
// src/modules/post/entities/post.entity.ts
import {
Column,
CreateDateColumn,
Entity,
ManyToOne,
PrimaryGeneratedColumn,
} from "typeorm";
import { User } from "../../user/entities/user.entity";
@Entity({ name: "posts" })
export class Post {
@PrimaryGeneratedColumn("uuid")
id!: string;
@Column()
title!: string;
@Column({ type: "text" })
content!: string;
@ManyToOne(() => User, (user) => user.posts, { onDelete: "CASCADE" })
author!: User;
@CreateDateColumn()
createdAt!: Date;
}
このスキルでは、次の点を推奨します。
- ID には
uuidまたは bigint を使用し、プロジェクトの方針に合わせて一貫させる onDelete、eager、lazyなどのリレーションオプションを、目的に応じて適切に使用する- エンティティに重いビジネスロジックを直接記述しない
4. モジュールとリポジトリの接続
TypeOrmModule.forFeature を使用して、機能モジュールにリポジトリを注入します。
// src/modules/user/user.module.ts
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { User } from "./entities/user.entity";
import { UserService } from "./user.service";
import { UserController } from "./user.controller";
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UserController],
providers: [UserService],
exports: [UserService],
})
export class UserModule {}
UserService では、リポジトリを注入します。
// src/modules/user/user.service.ts
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { User } from "./entities/user.entity";
import { CreateUserDto } from "./dto/create-user.dto";
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private readonly usersRepo: Repository<User>,
) {}
create(dto: CreateUserDto) {
const entity = this.usersRepo.create({
email: dto.email,
passwordHash: dto.passwordHash,
});
return this.usersRepo.save(entity);
}
findAll() {
return this.usersRepo.find();
}
findOne(id: string) {
return this.usersRepo.findOne({ where: { id } });
}
// etc...
}
このスキルでは、次の点を徹底します。
- リポジトリは手動でインスタンス化せず、DI 経由で注入する
- サービスは、(高度なケースを除き)データソースではなくリポジトリに依存する
5. マイグレーション
スキーマ変更には synchronize ではなく、マイグレーションの使用を推奨します。
- CLI マイグレーションに必要な場合は、
data-source.tsファイルを作成します。
// data-source.ts (or src/infrastructure/database/data-source.ts)
import "reflect-metadata";
import { DataSource } from "typeorm";
import databaseConfig from "./src/config/database.config";
import { config as loadEnv } from "dotenv";
loadEnv();
const db = databaseConfig();
export const AppDataSource = new DataSource({
type: "postgres",
host: db.database.host,
port: db.database.port,
username: db.database.username,
password: db.database.password,
database: db.database.database,
entities: ["src/**/*.entity.{ts,js}"],
migrations: ["migrations/*.{ts,js}"],
});
- マイグレーション用の
package.jsonスクリプトを追加します(正確な形式はプロジェクトによって異なります)。
{
"scripts": {
"typeorm:run": "typeorm-ts-node-commonjs migration:run -d data-source.ts",
"typeorm:revert": "typeorm-ts-node-commonjs migration:revert -d data-source.ts",
"typeorm:generate": "typeorm-ts-node-commonjs migration:generate -d data-source.ts migrations/AutoMigration"
}
}
このスキルでは、次のことを行います。
- スキーマ同期よりも、明示的なマイグレーション生成(
migration:generate)を優先します。 - マイグレーションファイルを小さく、順序立てて管理し、バージョン管理にコミットします。
6. トランザクションと複雑な操作
複数の DB 書き込みを必要とする操作では、このスキルで次のことを行います。
- 必要に応じて、
QueryRunnerまたはmanager.transactionを使用します。
例:
import { DataSource } from "typeorm";
@Injectable()
export class OrderService {
constructor(private readonly dataSource: DataSource) {}
async createOrderAndItems(dto: CreateOrderDto) {
return this.dataSource.transaction(async (manager) => {
const order = manager.create(Order, { /* ... */ });
await manager.save(order);
const items = dto.items.map((itemDto) =>
manager.create(OrderItem, {
order,
// ...
}),
);
await manager.save(items);
return order;
});
}
}
ガイドライン:
- トランザクションは必要な場合にのみ使用し、デフォルトですべてをトランザクションで囲むことは避けます。
- エラーが適切に伝播するように処理します。トランザクション内で例外が発生した場合はロールバックされます。
7. パフォーマンスとクエリのパターン
このスキルでは、次の使用を推奨します。
- 常にエンティティ全体を読み込むのではなく、
selectとプロジェクションを使用します。 - 必要に応じてリレーションの読み込みパターンを使い、N+1 クエリを回避します。
- 頻繁にクエリされる列には、マイグレーションでインデックスを追加します。
- 大規模なリストには、ページネーション戦略(offset/limit またはカーソルベース)を使用します。
8. 既存の TypeORM の使用方法のリファクタリング
リファクタリング時:
- アンチパターンを特定します。
- 接続の手動作成(Nest の DI を介さない)
- 注入されたリポジトリではなく、グローバルな
getRepositoryを直接使用する - 本番環境での
synchronize: true
- 次のものに置き換えます。
TypeOrmModuleの設定- 注入された
Repository<T>またはDataSource - スキーマ変更のためのマイグレーション
このスキルでは、構造を改善しながら、破壊的変更を最小限に抑えるよう努めます。
他のスキルとの連携
nestjs-project-scaffold:- Nest の基本構造を提供します。このスキルは、その構造に DB 設定を組み込みます。
nestjs-modules-services-controllers:- モジュールとサービスを使用します。このスキルは、それらのサービスの背後にエンティティとリポジトリを追加します。
nestjs-authentication:- ユーザーエンティティとユーザーリポジトリに依存します。このスキルは、そのレイヤーを提供します。
- TypeORM 固有のスキル(
typeorm-schema-design、typeorm-migrations-workflow):- より詳細な DB 設計やマイグレーション戦略のために、追加で使用できます。
このスキルを使用するプロンプトの例
- 「この NestJS アプリを TypeORM 経由で Postgres に接続し、User エンティティと Post エンティティを作成してください。」
- 「手作りの DB コードを、適切な TypeORM モジュールとサービスにリファクタリングしてください。」
- 「これらのスキーマ変更のマイグレーションを追加し、NestJS プロジェクトに組み込んでください。」
- 「注文とその明細を作成する、トランザクションを使用した操作を実装してください。」
- 「この TypeORM 設定を修正してください。ローカルでは動作しますが、本番環境では失敗します。」
このようなプロンプトでは、このスキルを活用して、堅牢で保守しやすく、本番環境に対応した NestJS + TypeORM の統合を設計・実装し、DB 以外の関心事は他のスキルに委ねます。