or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-source.mdentity-definition.mdentity-schema.mdevents.mdfind-options.mdindex.mdmigrations.mdquery-builder.mdrelationships.mdrepository.md

migrations.mddocs/

0

# Migration System

1

2

Database schema version control system for managing database structure changes, data migrations, and deployment workflows. TypeORM's migration system provides a robust way to evolve database schemas across environments.

3

4

## Capabilities

5

6

### Migration Interface

7

8

Core interface for implementing database migrations with up and down methods.

9

10

```typescript { .api }

11

/**

12

* Interface that all migration classes must implement

13

*/

14

interface MigrationInterface {

15

/**

16

* Applies the migration (forward direction)

17

* @param queryRunner - Query runner for database operations

18

* @returns Promise resolving when migration is applied

19

*/

20

up(queryRunner: QueryRunner): Promise<any>;

21

22

/**

23

* Reverts the migration (backward direction)

24

* @param queryRunner - Query runner for database operations

25

* @returns Promise resolving when migration is reverted

26

*/

27

down(queryRunner: QueryRunner): Promise<any>;

28

}

29

30

/**

31

* Migration metadata class

32

*/

33

class Migration {

34

/**

35

* Creates a new migration instance

36

* @param id - Migration ID (timestamp or number)

37

* @param timestamp - Migration timestamp

38

* @param name - Migration name

39

* @param instance - Migration implementation instance

40

*/

41

constructor(

42

id: number | string,

43

timestamp: number,

44

name: string,

45

instance?: MigrationInterface

46

);

47

48

/** Unique migration identifier */

49

readonly id: number | string;

50

51

/** Migration creation timestamp */

52

readonly timestamp: number;

53

54

/** Migration name/description */

55

readonly name: string;

56

57

/** Migration implementation instance */

58

readonly instance?: MigrationInterface;

59

}

60

```

61

62

**Migration Example:**

63

64

```typescript

65

import { MigrationInterface, QueryRunner } from "typeorm";

66

67

export class CreateUserTable1635123456789 implements MigrationInterface {

68

name = "CreateUserTable1635123456789";

69

70

public async up(queryRunner: QueryRunner): Promise<void> {

71

await queryRunner.query(`

72

CREATE TABLE "user" (

73

"id" SERIAL NOT NULL,

74

"name" character varying NOT NULL,

75

"email" character varying NOT NULL,

76

"created_at" TIMESTAMP NOT NULL DEFAULT now(),

77

"updated_at" TIMESTAMP NOT NULL DEFAULT now(),

78

CONSTRAINT "UQ_USER_EMAIL" UNIQUE ("email"),

79

CONSTRAINT "PK_USER" PRIMARY KEY ("id")

80

)

81

`);

82

}

83

84

public async down(queryRunner: QueryRunner): Promise<void> {

85

await queryRunner.query(`DROP TABLE "user"`);

86

}

87

}

88

```

89

90

### Migration Executor

91

92

Service class for executing, reverting, and managing migrations in production environments.

93

94

```typescript { .api }

95

/**

96

* Executes and manages database migrations

97

*/

98

class MigrationExecutor {

99

/** Data source connection */

100

readonly connection: DataSource;

101

102

/**

103

* Executes all pending migrations

104

* @returns Promise resolving to array of executed migrations

105

*/

106

executePendingMigrations(): Promise<Migration[]>;

107

108

/**

109

* Reverts the most recent migration

110

* @returns Promise resolving when migration is reverted

111

*/

112

undoLastMigration(): Promise<void>;

113

114

/**

115

* Shows migration status (executed vs pending)

116

* @returns Promise resolving to boolean indicating if migrations are pending

117

*/

118

showMigrations(): Promise<boolean>;

119

120

/**

121

* Gets all migrations from files and database

122

* @returns Promise resolving to migrations array

123

*/

124

getAllMigrations(): Promise<Migration[]>;

125

126

/**

127

* Gets executed migrations from database

128

* @returns Promise resolving to executed migrations

129

*/

130

getExecutedMigrations(): Promise<Migration[]>;

131

132

/**

133

* Gets pending migrations that haven't been executed

134

* @returns Promise resolving to pending migrations

135

*/

136

getPendingMigrations(): Promise<Migration[]>;

137

138

/**

139

* Creates migrations table if it doesn't exist

140

* @returns Promise resolving when table is created

141

*/

142

createMigrationsTableIfNotExist(): Promise<void>;

143

144

/**

145

* Loads migration files from filesystem

146

* @returns Promise resolving to migration instances

147

*/

148

loadMigrations(): Promise<Migration[]>;

149

150

/**

151

* Executes a specific migration

152

* @param migration - Migration to execute

153

* @returns Promise resolving when migration is executed

154

*/

155

executeMigration(migration: Migration): Promise<void>;

156

157

/**

158

* Reverts a specific migration

159

* @param migration - Migration to revert

160

* @returns Promise resolving when migration is reverted

161

*/

162

undoMigration(migration: Migration): Promise<void>;

163

}

164

```

165

166

### Query Runner

167

168

Low-level interface for executing database operations during migrations.

169

170

```typescript { .api }

171

/**

172

* Query runner for database operations in migrations

173

*/

174

interface QueryRunner {

175

/** Data source connection */

176

connection: DataSource;

177

178

/** Current database connection */

179

databaseConnection: any;

180

181

/** Whether runner is released */

182

isReleased: boolean;

183

184

/** Whether runner is in transaction */

185

isTransactionActive: boolean;

186

187

/**

188

* Starts a new database transaction

189

* @returns Promise resolving when transaction is started

190

*/

191

startTransaction(): Promise<void>;

192

193

/**

194

* Commits current transaction

195

* @returns Promise resolving when transaction is committed

196

*/

197

commitTransaction(): Promise<void>;

198

199

/**

200

* Rolls back current transaction

201

* @returns Promise resolving when transaction is rolled back

202

*/

203

rollbackTransaction(): Promise<void>;

204

205

/**

206

* Executes raw SQL query

207

* @param query - SQL query string

208

* @param parameters - Query parameters

209

* @returns Promise resolving to query results

210

*/

211

query(query: string, parameters?: any[]): Promise<any>;

212

213

/**

214

* Creates a new database table

215

* @param table - Table definition

216

* @param ifNotExist - Whether to use IF NOT EXISTS clause

217

* @returns Promise resolving when table is created

218

*/

219

createTable(table: Table, ifNotExist?: boolean): Promise<void>;

220

221

/**

222

* Drops an existing database table

223

* @param tableOrName - Table instance or name

224

* @param ifExist - Whether to use IF EXISTS clause

225

* @returns Promise resolving when table is dropped

226

*/

227

dropTable(tableOrName: Table | string, ifExist?: boolean): Promise<void>;

228

229

/**

230

* Adds a new column to existing table

231

* @param tableOrName - Table instance or name

232

* @param column - Column definition

233

* @returns Promise resolving when column is added

234

*/

235

addColumn(tableOrName: Table | string, column: TableColumn): Promise<void>;

236

237

/**

238

* Drops column from existing table

239

* @param tableOrName - Table instance or name

240

* @param columnOrName - Column instance or name

241

* @returns Promise resolving when column is dropped

242

*/

243

dropColumn(tableOrName: Table | string, columnOrName: TableColumn | string): Promise<void>;

244

245

/**

246

* Creates a database index

247

* @param tableOrName - Table instance or name

248

* @param index - Index definition

249

* @returns Promise resolving when index is created

250

*/

251

createIndex(tableOrName: Table | string, index: TableIndex): Promise<void>;

252

253

/**

254

* Drops a database index

255

* @param tableOrName - Table instance or name

256

* @param indexOrName - Index instance or name

257

* @returns Promise resolving when index is dropped

258

*/

259

dropIndex(tableOrName: Table | string, indexOrName: TableIndex | string): Promise<void>;

260

261

/**

262

* Creates a foreign key constraint

263

* @param tableOrName - Table instance or name

264

* @param foreignKey - Foreign key definition

265

* @returns Promise resolving when foreign key is created

266

*/

267

createForeignKey(tableOrName: Table | string, foreignKey: TableForeignKey): Promise<void>;

268

269

/**

270

* Drops a foreign key constraint

271

* @param tableOrName - Table instance or name

272

* @param foreignKeyOrName - Foreign key instance or name

273

* @returns Promise resolving when foreign key is dropped

274

*/

275

dropForeignKey(tableOrName: Table | string, foreignKeyOrName: TableForeignKey | string): Promise<void>;

276

277

/**

278

* Releases the query runner and closes connection

279

* @returns Promise resolving when runner is released

280

*/

281

release(): Promise<void>;

282

}

283

```

284

285

### Schema Builder Classes

286

287

Classes for defining database schema elements in migrations.

288

289

```typescript { .api }

290

/**

291

* Database table definition for migrations

292

*/

293

class Table {

294

constructor(options: {

295

name: string;

296

columns: TableColumn[];

297

indices?: TableIndex[];

298

foreignKeys?: TableForeignKey[];

299

uniques?: TableUnique[];

300

checks?: TableCheck[];

301

exclusions?: TableExclusion[];

302

engine?: string;

303

database?: string;

304

schema?: string;

305

});

306

307

name: string;

308

columns: TableColumn[];

309

indices: TableIndex[];

310

foreignKeys: TableForeignKey[];

311

uniques: TableUnique[];

312

checks: TableCheck[];

313

exclusions: TableExclusion[];

314

}

315

316

/**

317

* Database column definition for migrations

318

*/

319

class TableColumn {

320

constructor(options: {

321

name: string;

322

type: ColumnType;

323

length?: string | number;

324

precision?: number;

325

scale?: number;

326

default?: any;

327

isNullable?: boolean;

328

isPrimary?: boolean;

329

isGenerated?: boolean;

330

generationStrategy?: "increment" | "uuid" | "rowid";

331

isUnique?: boolean;

332

comment?: string;

333

collation?: string;

334

charset?: string;

335

});

336

337

name: string;

338

type: ColumnType;

339

length?: string | number;

340

isNullable: boolean;

341

isPrimary: boolean;

342

default?: any;

343

}

344

345

/**

346

* Database index definition for migrations

347

*/

348

class TableIndex {

349

constructor(options: {

350

name?: string;

351

columnNames: string[];

352

isUnique?: boolean;

353

isSpatial?: boolean;

354

isFulltext?: boolean;

355

where?: string;

356

using?: string;

357

});

358

359

name?: string;

360

columnNames: string[];

361

isUnique: boolean;

362

}

363

364

/**

365

* Foreign key constraint definition for migrations

366

*/

367

class TableForeignKey {

368

constructor(options: {

369

name?: string;

370

columnNames: string[];

371

referencedTableName: string;

372

referencedColumnNames: string[];

373

onDelete?: "RESTRICT" | "CASCADE" | "SET NULL" | "SET DEFAULT" | "NO ACTION";

374

onUpdate?: "RESTRICT" | "CASCADE" | "SET NULL" | "SET DEFAULT" | "NO ACTION";

375

});

376

377

name?: string;

378

columnNames: string[];

379

referencedTableName: string;

380

referencedColumnNames: string[];

381

onDelete?: string;

382

onUpdate?: string;

383

}

384

```

385

386

**Schema Building Example:**

387

388

```typescript

389

import { MigrationInterface, QueryRunner, Table, TableColumn, TableIndex, TableForeignKey } from "typeorm";

390

391

export class CreatePostsTable1635123456790 implements MigrationInterface {

392

public async up(queryRunner: QueryRunner): Promise<void> {

393

await queryRunner.createTable(

394

new Table({

395

name: "post",

396

columns: [

397

new TableColumn({

398

name: "id",

399

type: "int",

400

isPrimary: true,

401

isGenerated: true,

402

generationStrategy: "increment"

403

}),

404

new TableColumn({

405

name: "title",

406

type: "varchar",

407

length: "255"

408

}),

409

new TableColumn({

410

name: "content",

411

type: "text"

412

}),

413

new TableColumn({

414

name: "author_id",

415

type: "int"

416

}),

417

new TableColumn({

418

name: "published_at",

419

type: "timestamp",

420

isNullable: true

421

}),

422

new TableColumn({

423

name: "created_at",

424

type: "timestamp",

425

default: "CURRENT_TIMESTAMP"

426

})

427

]

428

})

429

);

430

431

await queryRunner.createIndex(

432

"post",

433

new TableIndex({

434

name: "IDX_POST_TITLE",

435

columnNames: ["title"]

436

})

437

);

438

439

await queryRunner.createForeignKey(

440

"post",

441

new TableForeignKey({

442

columnNames: ["author_id"],

443

referencedTableName: "user",

444

referencedColumnNames: ["id"],

445

onDelete: "CASCADE"

446

})

447

);

448

}

449

450

public async down(queryRunner: QueryRunner): Promise<void> {

451

await queryRunner.dropTable("post");

452

}

453

}

454

```

455

456

## Migration Commands

457

458

TypeORM provides CLI commands for migration management:

459

460

### CLI Commands

461

462

```bash

463

# Generate a new migration based on entity changes

464

typeorm migration:generate -n CreateUserTable

465

466

# Create an empty migration file

467

typeorm migration:create -n AddIndexToUser

468

469

# Run pending migrations

470

typeorm migration:run

471

472

# Revert last migration

473

typeorm migration:revert

474

475

# Show migration status

476

typeorm migration:show

477

```

478

479

### Programmatic Usage

480

481

```typescript

482

// Execute migrations programmatically

483

const dataSource = new DataSource({

484

// connection options

485

migrations: ["src/migrations/*.ts"],

486

migrationsRun: true // Automatically run migrations on startup

487

});

488

489

await dataSource.initialize();

490

491

// Manual migration execution

492

await dataSource.runMigrations();

493

494

// Revert migrations

495

await dataSource.undoLastMigration();

496

497

// Check pending migrations

498

const pendingMigrations = await dataSource.showMigrations();

499

```

500

501

## Migration Best Practices

502

503

### Safe Migration Patterns

504

505

```typescript

506

export class SafeColumnAddition1635123456791 implements MigrationInterface {

507

public async up(queryRunner: QueryRunner): Promise<void> {

508

// Add nullable column first

509

await queryRunner.addColumn("user", new TableColumn({

510

name: "phone",

511

type: "varchar",

512

length: "20",

513

isNullable: true

514

}));

515

516

// Populate data if needed

517

await queryRunner.query(`

518

UPDATE "user" SET "phone" = '' WHERE "phone" IS NULL

519

`);

520

521

// Make column non-nullable if required

522

await queryRunner.changeColumn("user", "phone", new TableColumn({

523

name: "phone",

524

type: "varchar",

525

length: "20",

526

isNullable: false,

527

default: "''"

528

}));

529

}

530

531

public async down(queryRunner: QueryRunner): Promise<void> {

532

await queryRunner.dropColumn("user", "phone");

533

}

534

}

535

```

536

537

### Data Migrations

538

539

```typescript

540

export class MigrateUserData1635123456792 implements MigrationInterface {

541

public async up(queryRunner: QueryRunner): Promise<void> {

542

// Get all users

543

const users = await queryRunner.query(`SELECT * FROM "user"`);

544

545

// Process data in batches

546

for (let i = 0; i < users.length; i += 100) {

547

const batch = users.slice(i, i + 100);

548

549

for (const user of batch) {

550

// Transform and update data

551

const transformedData = transformUserData(user);

552

await queryRunner.query(

553

`UPDATE "user" SET "new_field" = $1 WHERE "id" = $2`,

554

[transformedData.newField, user.id]

555

);

556

}

557

}

558

}

559

560

public async down(queryRunner: QueryRunner): Promise<void> {

561

// Revert data changes

562

await queryRunner.query(`UPDATE "user" SET "new_field" = NULL`);

563

}

564

}