Skip to main content

Automatic migration planning for TypeORM

TL;DR

  • TypeORM is an ORM for TypeScript and JavaScript that can run in many platforms (Node.js, Browser, React Native, NativeScript, and more).
  • Atlas is an open-source tool for inspecting, planning, linting and executing schema changes to your database.
  • Developers using TypeORM can use Atlas to automatically plan schema migrations for them, based on the desired state of their schema instead of crafting them by hand.

Automatic migration planning for TypeORM

TypeORM is a popular ORM widely used in the Node.js community. TypeORM allows users to manage their database schemas using its schema-synchronization feature, which is usually sufficient during development and in many simple cases.

However, at some point, teams need more control and decide to employ the migrations methodology, which is a more robust way to manage your database schema. TypeORM allows users to generate migration files based on the difference between the current state of the database and the desired state.

In order to apply the schema migrations to the CI/CD pipeline, developers need to manually craft scripts that will execute the migrations against the production database and handle failures manually.

Atlas has many features that can help developers manage their database CI/CD pipelines more easily:

  • Declarative migrations - use a Terraform-like atlas schema apply flow to manage your database.
  • Diff policies - provide Atlas with policies for planning schema changes (such as "always create index concurrently" or "do not drop columns").
  • CI for schema changes - Atlas can be used during CI to make sure you never merge a pull request.
  • Modern CD integrations - Atlas integrates seamlessly with modern deployment tools such as Kubernetes, Terraform, Helm, Flux, and ArgoCD. This allows you to deploy changes to your database schema as part of your existing deployment pipelines.
  • Visualization - Atlas users can create beautiful, shareable ERDs of their application data model

In this guide, we will show how Atlas can be used to automatically plan schema migrations for TypeORM users.

Prerequisites

If you don't have a TypeORM project handy, you can use typeorm/typescript-express-example as a starting point:

git clone git@github.com:typeorm/typescript-express-example.git

Using the Atlas TypeORM Provider

In this guide, we will use the TypeORM Atlas Provider to automatically plan schema migrations for a TypeORM project.

Installation

Install Atlas from macOS or Linux by running:

curl -sSf https://atlasgo.sh | sh

See atlasgo.io for more installation options.

Install the provider by running:

npm install @ariga/atlas-provider-typeorm

Make sure all your Node dependencies are installed by running:

npm install

Standalone vs Script mode

The Atlas TypeORM Provider can be used in two modes:

  • Standalone - If all of your TypeORM entities exist in a single Node module, you can use the provider directly to load your TypeORM schema into Atlas.
  • Script - In other cases, you can use the provider as an npm package to write a script that loads your TypeORM schema into Atlas.

Standalone mode

In your project directory, create a new file named atlas.hcl with the following contents:

data "external_schema" "typeorm" {
program = [
"npx",
"@ariga/atlas-provider-typeorm",
"load",
"--path", "./path/to/entities",
"--dialect", "mysql", // mariadb | postgres | sqlite | mssql
]
}

env "typeorm" {
src = data.external_schema.typeorm.url
dev = "docker://mysql/8/dev"
migration {
dir = "file://migrations"
}
format {
migrate {
diff = "{{ sql . \" \" }}"
}
}
}

Script mode

Create a new file named load.js with the following contents:

#!/usr/bin/env node

const loadEntities = require("@ariga/atlas-provider-typeorm/build/load").loadEntities;
const EntitySchema = require("typeorm").EntitySchema;

// require typeorm entities you want to load
const user = new EntitySchema(require("./entities/User"));
const blog = new EntitySchema(require("./entities/Blog"));

loadEntities("mysql", [user, blog]).then((sql) => {
console.log(sql);
});

Next, in your project directory, create a new file named atlas.hcl with the following contents:

data "external_schema" "typeorm" {
program = [
"node",
"load.js",
]
}

env "typeorm" {
src = data.external_schema.typeorm.url
dev = "docker://mysql/8/dev"
migration {
dir = "file://migrations"
}
format {
migrate {
diff = "{{ sql . \" \" }}"
}
}
}

Usage

Atlas supports a versioned migrations workflow, where each change to the database is versioned and recorded in a migration file. You can use the atlas migrate diff command to automatically generate a migration file that will migrate the database from its latest revision to the current TypeORM schema.

Suppose we have the following TypeORM entities directory, with two entities Blog and User:

module.exports = {
name: "Blog",
columns: {
id: {
primary: true,
type: "int",
generated: true,
},
title: {
type: "varchar",
},
},
relations: {
project: {
type: "many-to-one",
target: "User",
joinColumn: {
name: "userId",
},
inverseSide: "blogs",
},
},
};

Using the Standalone mode configuration file for the Atlas TypeORM Provider, we can generate a migration file by running this command:

atlas migrate diff --env typeorm

Running this command will generate files similar to this in the migrations directory:

migrations
|-- 20230918143104.sql
`-- atlas.sum

0 directories, 2 files

Examining the contents of 20230918143104.sql:

-- Create "user" table
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`firstName` varchar(255) NOT NULL,
`lastName` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
-- Create "blog" table
CREATE TABLE `blog` (
`id` int NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`userId` int NULL,
PRIMARY KEY (`id`),
INDEX `FK_fc46ede0f7ab797b7ffacb5c08d` (`userId`),
CONSTRAINT `FK_fc46ede0f7ab797b7ffacb5c08d` FOREIGN KEY (`userId`) REFERENCES `user` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION
) CHARSET utf8mb4 COLLATE utf8mb4_0900_ai_ci;

Amazing! Atlas automatically generated a migration file that will create the User and Blog tables in our database!

Next, alter the User entity to add a new age field:

    lastName: {
type: "varchar",
},
+ age: {
+ type: "int",
+ }

Re-run this command:

atlas migrate diff --env typeorm

Observe a new migration file is generated:

-- Modify "user" table
ALTER TABLE `user` ADD COLUMN `age` int NOT NULL;

Conclusion

In this guide we demonstrated how projects using TypeORM can use Atlas to automatically plan schema migrations based only on their data model. To learn more about executing these migrations against your production database, read the documentation for the migrate apply command.

Have questions? Feedback? Find our team on our Discord server