Understanding Sync vs Migration in NestJS with TypeORM: A Comprehensive Guide

When working with databases in NestJS and TypeORM, there are two common approaches to managing changes in the database schema: Synchronization (Sync) and Migrations. These two methods help developers align the database structure with the entities in the code, but they serve different purposes and have distinct use cases.

In this blog post, we will explore the differences between synchronization and migrations in the context of NestJS and TypeORM, providing code examples, pros and cons, and insights into when to use each approach.


1. Introduction to TypeORM in NestJS

NestJS is a progressive Node.js framework that helps build scalable and maintainable server-side applications. It works seamlessly with TypeORM, a popular ORM (Object-Relational Mapper) for TypeScript and JavaScript, which simplifies interactions with databases.

TypeORM allows developers to define the schema of a database in the form of entities. Once entities are defined, the database structure can be synchronized with the application using either sync (automatic) or migration (manual) methods.


2. What is Synchronization in TypeORM?

Synchronization is a feature in TypeORM that automatically updates the database schema whenever you change your entities. This means that when you modify your entity classes, TypeORM automatically adjusts the underlying database structure.

In NestJS, you can enable synchronization by setting the synchronize option to true in the TypeORM configuration file. Here’s a simple example.

Code Example: Enabling Synchronization

import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres', // Database type
      host: 'localhost',
      port: 5432,
      username: 'user',
      password: 'password',
      database: 'mydb',
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true, // Enable synchronization
    }),
  ],
})
export class AppModule {}

With synchronization enabled, TypeORM will check the entities defined in your application and automatically create or alter tables in the database when you start the application.

Pros of Synchronization:

  • Automatic Updates: Schema changes are immediately applied without additional commands.

  • Fast Development: Ideal for early stages of development when schema changes are frequent.

  • Simplified Workflow: No need to write migration files manually.

Cons of Synchronization:

  • Not Suitable for Production: Sync is not recommended for production environments because any change in entities can accidentally drop data or result in unintended modifications.

  • Lack of Control: You have less control over what exactly gets changed in the database schema.

  • Risk of Data Loss: When altering or deleting tables, there's a risk of data loss since sync doesn’t always preserve data.


3. What are Migrations in TypeORM?

Migrations in TypeORM provide a more controlled and production-safe way to update the database schema. Instead of automatically applying changes to the database, you generate migration files that contain the necessary SQL commands to update the schema. These migrations are manually executed when required, giving you more control over how and when schema changes are applied.

Code Example: Generating and Running Migrations

Here’s how you can use migrations in NestJS with TypeORM.

  1. Generate a Migration

First, make sure to configure TypeORM without enabling synchronization:

import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'postgres',
      host: 'localhost',
      port: 5432,
      username: 'user',
      password: 'password',
      database: 'mydb',
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: false, // Disable synchronization
    }),
  ],
})
export class AppModule {}

Now, whenever you modify your entities, you need to generate a migration:

npx typeorm migration:generate -n CreateUserTable
  1. Run the Migration

Once the migration is generated, you can run it:

npx typeorm migration:run

Migration File Example

Here’s an example of a migration file generated by TypeORM:

import { MigrationInterface, QueryRunner } from 'typeorm';

export class CreateUserTable1658886886786 implements MigrationInterface {
  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      CREATE TABLE "user" (
        "id" SERIAL NOT NULL,
        "username" character varying NOT NULL,
        "email" character varying NOT NULL,
        "password" character varying NOT NULL,
        PRIMARY KEY ("id")
      )
    `);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`DROP TABLE "user"`);
  }
}

Pros of Migrations:

  • Control: You have complete control over the database schema and can review the changes before applying them.

  • Safe for Production: Migrations can be tested on staging environments before running them in production.

  • Rollback: You can easily roll back a migration if something goes wrong.

Cons of Migrations:

  • Manual Process: You need to generate and apply migrations manually.

  • Additional Overhead: Involves more steps compared to the synchronization method.

  • Potential for Human Error: Mistakes can occur when generating or modifying migrations.


4. Key Differences Between Synchronization and Migrations

FeatureSynchronizationMigrations
Automatic Schema UpdatesYesNo (manual)
Production SuitabilityNot recommendedHighly recommended
Control Over ChangesLess controlFull control
Rollback CapabilityNoYes
Risk of Data LossHigh, especially in productionLow, as changes can be thoroughly tested
Ease of UseEasy and quick to useRequires more effort
FlexibilityLess flexible; applies changes immediatelyMore flexible; allows versioning

5. When to Use Sync vs Migration

  • Use Synchronization (Sync) during early development stages where the database schema is changing frequently. This allows for quick iterations and fast feedback on changes. However, switch to migrations as the project matures.

  • Use Migrations when your project is moving into production or when you need more control over how schema changes are applied. Migrations offer a safer way to manage changes, with rollback options and a clearer versioning mechanism.


6. Best Practices for Managing Database Schema Changes

  • Development Environment: Use synchronize: true for rapid development and testing but switch it off before deploying to production.

  • Staging and Production: Always use migrations for production environments. Migrations allow you to track and manage schema changes systematically.

  • Test Migrations: Run migrations in a staging environment before applying them to production. This ensures you catch any potential issues early.

  • Version Control for Migrations: Keep your migration files under version control (e.g., Git) to track the history of schema changes across your team.

  • Backup Your Database: Before applying migrations in production, always back up your database to prevent data loss in case something goes wrong.


Conclusion
In summary, synchronization in TypeORM is a convenient feature for early-stage development, but migrations are essential for production environments due to their control, safety, and rollback capabilities. While synchronization helps developers iterate quickly, migrations ensure that database schema changes are applied in a predictable and controlled manner.

Understanding when to use each approach is key to managing database changes effectively in NestJS applications. By following best practices and carefully planning your database updates, you can avoid potential pitfalls and ensure smooth database management in your project.

Happy coding!

0
Subscribe to my newsletter

Read articles from ByteScrum Technologies directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

ByteScrum Technologies
ByteScrum Technologies

Our company comprises seasoned professionals, each an expert in their field. Customer satisfaction is our top priority, exceeding clients' needs. We ensure competitive pricing and quality in web and mobile development without compromise.