Database Migrations in TypeScript: TypeORM, Prisma, and Drizzle

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Database Migrations in TypeScript: A Complete Overview of Tools and Practical Guide



Database migrations are a way to version and sequentially apply changes to a database schema (creating, modifying, or deleting tables, indexes, and constraints). In the TypeScript ecosystem, there are several powerful tools for managing migrations. In this article, we will take a detailed look at three of the most popular solutions: TypeORM, Prisma, and Drizzle ORM.



Why are migrations needed?

Without migrations, developers often make changes manually via an SQL console or admin panel, which leads to:

  • Loss of synchronization between the development environment and production;
  • Errors due to human factors;
  • Difficulties when rolling back changes.

Migrations solve these problems by allowing you to automatically apply and roll back changes, as well as store the history of all schema changes in code.



1. TypeORM — The Classic Approach with ActiveRecord and Data Mapper

TypeORM is one of the most mature ORMs for TypeScript and JavaScript. It supports both the ActiveRecord and Data Mapper patterns and has a built-in migration system.



Installation and Setup

npm install typeorm reflect-metadata @types/nodenpm install pg  # for PostgreSQL


Create a configuration file ormconfig.json or use data-source.ts:

import { DataSource } from "typeorm";

export const AppDataSource = new DataSource({ type: "postgres", host: "localhost", port: 5432, username: "user", password: "password", database: "mydb", entities: ["src/entity/*.ts"], migrations: ["src/migration/*.ts"], synchronize: false, // disable auto-synchronization});


Creating and Running a Migration

First, generate a migration based on changes in entities:

npx typeorm migration:generate src/migration/AddUserTable -d src/data-source.ts


Example of a generated migration:

import { MigrationInterface, QueryRunner, Table } from "typeorm";

export class AddUserTable1234567890 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise<void> { await queryRunner.createTable( new Table({ name: "user", columns: [ { name: "id", type: "int", isPrimary: true, isGenerated: true, generationStrategy: "increment" }, { name: "name", type: "varchar", length: "255" }, { name: "email", type: "varchar", isUnique: true }, ], }) ); }

public async down(queryRunner: QueryRunner): Promise<void> { await queryRunner.dropTable("user"); }}


Apply the migration:

npx typeorm migration:run -d src/data-source.ts


Pros and Cons of TypeORM

  • Pros: large ecosystem, many databases (PostgreSQL, MySQL, SQLite, MSSQL), migration generation from entities.
  • Cons: complex configuration, slow performance with a large number of entities, outdated codebase.


2. Prisma — Modern ORM with Automatic Migrations

Prisma is the new standard in TypeScript ORMs. It uses a declarative schema (schema.prisma) and automatically generates migrations.



Installation and Initialization

npm install prisma @prisma/clientnpx prisma init


Define the model in prisma/schema.prisma:

generator client {    provider = "prisma-client-js"}

datasource db { provider = "postgresql" url = env("DATABASE_URL")}

model User { id

Recommendations