Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
40 prioritized NestJS best practices across architecture, DI, security, performance, testing, and microservices.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/db-use-migrations.md
1---2title: Use Database Migrations3impact: HIGH4impactDescription: Enables safe, repeatable database schema changes5tags: database, migrations, typeorm, schema6---78## Use Database Migrations910Never use `synchronize: true` in production. Use migrations for all schema changes. Migrations provide version control for your database, enable safe rollbacks, and ensure consistency across all environments.1112**Incorrect (using synchronize or manual SQL):**1314```typescript15// Use synchronize in production16TypeOrmModule.forRoot({17type: 'postgres',18synchronize: true, // DANGEROUS in production!19// Can drop columns, tables, or data20});2122// Manual SQL in production23@Injectable()24export class DatabaseService {25async addColumn(): Promise<void> {26await this.dataSource.query('ALTER TABLE users ADD COLUMN age INT');27// No version control, no rollback, inconsistent across envs28}29}3031// Modify entities without migration32@Entity()33export class User {34@Column()35email: string;3637@Column() // Added without migration38newField: string; // Will crash in production if synchronize is false39}40```4142**Correct (use migrations for all schema changes):**4344```typescript45// Configure TypeORM for migrations46// data-source.ts47export const dataSource = new DataSource({48type: 'postgres',49host: process.env.DB_HOST,50port: parseInt(process.env.DB_PORT),51username: process.env.DB_USERNAME,52password: process.env.DB_PASSWORD,53database: process.env.DB_NAME,54entities: ['dist/**/*.entity.js'],55migrations: ['dist/migrations/*.js'],56synchronize: false, // Always false in production57migrationsRun: true, // Run migrations on startup58});5960// app.module.ts61TypeOrmModule.forRootAsync({62inject: [ConfigService],63useFactory: (config: ConfigService) => ({64type: 'postgres',65host: config.get('DB_HOST'),66synchronize: config.get('NODE_ENV') === 'development', // Only in dev67migrations: ['dist/migrations/*.js'],68migrationsRun: true,69}),70});7172// migrations/1705312800000-AddUserAge.ts73import { MigrationInterface, QueryRunner } from 'typeorm';7475export class AddUserAge1705312800000 implements MigrationInterface {76name = 'AddUserAge1705312800000';7778public async up(queryRunner: QueryRunner): Promise<void> {79// Add column with default to handle existing rows80await queryRunner.query(`81ALTER TABLE "users" ADD "age" integer DEFAULT 082`);8384// Add index for frequently queried columns85await queryRunner.query(`86CREATE INDEX "IDX_users_age" ON "users" ("age")87`);88}8990public async down(queryRunner: QueryRunner): Promise<void> {91// Always implement down for rollback92await queryRunner.query(`DROP INDEX "IDX_users_age"`);93await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "age"`);94}95}9697// Safe column rename (two-step)98export class RenameNameToFullName1705312900000 implements MigrationInterface {99public async up(queryRunner: QueryRunner): Promise<void> {100// Step 1: Add new column101await queryRunner.query(`102ALTER TABLE "users" ADD "full_name" varchar(255)103`);104105// Step 2: Copy data106await queryRunner.query(`107UPDATE "users" SET "full_name" = "name"108`);109110// Step 3: Add NOT NULL constraint111await queryRunner.query(`112ALTER TABLE "users" ALTER COLUMN "full_name" SET NOT NULL113`);114115// Step 4: Drop old column (after verifying app works)116await queryRunner.query(`117ALTER TABLE "users" DROP COLUMN "name"118`);119}120121public async down(queryRunner: QueryRunner): Promise<void> {122await queryRunner.query(`ALTER TABLE "users" ADD "name" varchar(255)`);123await queryRunner.query(`UPDATE "users" SET "name" = "full_name"`);124await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "full_name"`);125}126}127```128129Reference: [TypeORM Migrations](https://typeorm.io/migrations)130