ts-migrate-mongoose
v5.2.0
Published
A migration framework for Mongoose, built with TypeScript.
Maintainers
Readme
ts-migrate-mongoose
A migration framework for Mongoose, built with TypeScript.
Motivation
ts-migrate-mongoose is a migration framework for mongoose
I need a way to manage database migrations for mongoose models, run them from the CLI or programmatically, and keep track of which migrations have been applied. It should support both ESM and CommonJS, work with all major Node.js frameworks, and be flexible enough to handle complex migration scenarios.
Supports and tested with
{
"node": "20.x || 22.x || 24.x",
"mongoose": ">=6.6.x || 7.x || 8.x || 9.x",
}Features
- Stores migration state in MongoDB
- Flexible configuration using
migrate.json,migrate.ts,.env - Utilizes mongoose models during migrations
- Supports async/await in migrations
- Run migrations from the CLI or programmatically
- Prune old migrations and sync new migrations
- Create custom templates for migrations
- Run individual migration up/down using -s, --single
- Supports ESM and CommonJS
Installation
mongoose is a peer dependency — install it alongside ts-migrate-mongoose.
npm install ts-migrate-mongoose mongoose
pnpm add ts-migrate-mongoose mongoose
yarn add ts-migrate-mongoose mongoose
bun add ts-migrate-mongoose mongooseOr globally:
npm install -g ts-migrate-mongoose mongoose
pnpm add -g ts-migrate-mongoose mongoose
yarn global add ts-migrate-mongoose mongoose
bun add -g ts-migrate-mongoose mongooseExample
Works with any Node.js framework — Express, Fastify, Koa, Hono, Nest, etc.
How to use it with:
- Express: ts-express-tsx, ts-express-esbuild
- Nest: ts-express-nest
Migrations and alias imports
If you are using alias imports in your project, you can use tsconfig.json paths to resolve them for your project.
Configuration
If you don't want to provide -d or --uri flag in CLI or Programmatic mode, you can configure it.
Create a migrate.json or migrate.ts or .env file in the root of your project:
migrate.json
{
"uri": "mongodb://localhost/my-db",
"collection": "migrations",
"migrationsPath": "./migrations",
"templatePath": "./migrations/template.ts",
"autosync": false
}migrate.ts
export default {
uri: "mongodb://localhost/my-db",
collection: "migrations",
migrationsPath: "./migrations",
templatePath: "./migrations/template.ts",
autosync: false,
connectOptions: {
autoIndex: true,
},
};.env
# You can set this variable or in your CI/CD pipeline
# Or use --mode flag in CLI mode to switch between .env files
MIGRATE_MODE=developmentIf mode is set, it will look for .env.[mode] file in the root of your project
For example, if MIGRATE_MODE=development it will look for .env.development file
If mode is not set, it will look for .env file in the root of your project
.env # loaded in all cases
.env.local # loaded in all cases (used as override for local development)
.env.[mode] # only loaded in specified mode
.env.[mode].local # only loaded in specified mode (used as override for local development)# Example .env file content
MIGRATE_MONGO_URI=mongodb://localhost/my-db
MIGRATE_MONGO_COLLECTION=migrations
MIGRATE_CONFIG_PATH=./migrate
MIGRATE_MIGRATIONS_PATH=./migrations
MIGRATE_TEMPLATE_PATH=./migrations/template.ts
MIGRATE_AUTOSYNC=false| Config file | .env / export | Default | Required | Description |
| -------------------- | ------------------------ | ------------ | -------- | ------------------------------------------------ |
| mode | MIGRATE_MODE | - | No | environment mode to use .env.[mode] file |
| uri | MIGRATE_MONGO_URI | - | Yes | mongo connection string |
| collection | MIGRATE_MONGO_COLLECTION | migrations | No | collection name to use for the migrations |
| configPath | MIGRATE_CONFIG_PATH | - | No | will lookup ./migrate[.ts,.js,.json] in root |
| migrationsPath | MIGRATE_MIGRATIONS_PATH | ./migrations | No | path to the migration files |
| templatePath | MIGRATE_TEMPLATE_PATH | - | No | template file to use when creating a migration |
| autosync | MIGRATE_AUTOSYNC | false | No | automatically sync new migrations without prompt |
| connectOptions | - | - | No | mongoose connection options (config file only) |
Getting started with the CLI
Explore and learn commands, rest of the tutorial will be using npm
npx migrate -h
pnpm migrate -h
yarn migrate -h
bun migrate -hCLI migration tool for mongoose
Usage: migrate <command> [options]
Commands:
list list all migrations
create <migration-name> create a new migration file
up [migration-name] run all migrations or a specific migration if name provided
down <migration-name> roll back migrations down to given name
prune delete extraneous migrations from migration folder or database
Options:
-f, --config-path <path> path to the config file
-d, --uri <string> mongo connection string
-c, --collection <string> collection name to use for the migrations
-a, --autosync <boolean> automatically sync new migrations without prompt
-m, --migrations-path <path> path to the migration files
-t, --template-path <path> template file to use when creating a migration
--mode <string> environment mode to use .env.[mode] file
-s, --single run single migration (up/down only)
-h, --help display help
-v, --version display versionBefore you start make sure you setup .env file or migrate.ts/json file so you don't need to provide -d on each command
npx migrate create add-users -d mongodb://localhost/my-dbIn case you want to run just one migration up or down use option --single
npx migrate create first-migration
npx migrate create second-migration
npx migrate list
npx migrate up second-migration -s # will migrate up only second-migration
npx migrate down second-migration -s # will migrate down only second-migration
npx migrate up -s # will migrate up first-migrationOptions override order
Note that options are overridden in the following order:
- Command line args > Env vars > Config file
Migration files
This example demonstrates how you can create a migration file using the CLI
By default, ts-migrate-mongoose assumes your migration folder exists (if it does not it will create one for you)
Here's an example of a migration created using:
npx migrate create first-migration
pnpm migrate create first-migration
yarn migrate create first-migration
bun migrate create first-migrationExecuting the above command will create a migration file in the ./migrations folder with the following content:
- 1673525773572-first-migration.ts
// Import your schemas here
import type { Connection } from 'mongoose'
export async function up (connection: Connection): Promise<void> {
// Write migration here
}
export async function down (connection: Connection): Promise<void> {
// Write migration here
}Using mongoose models in your migrations
As long as you can import the references to your models you can use them in migrations
Below is an example of a typical setup in a mongoose project:
- models/User.ts - defines the User model
import { Schema, model, models } from 'mongoose'
interface IUser {
firstName: string
lastName?: string
}
export const UserSchema = new Schema<IUser>({
firstName: {
type: String,
required: true
},
lastName: {
type: String
}
})
export default models.User ?? model<IUser>('User', UserSchema)- 1673525773572-first-migration-demo.ts - your migration file
import { UserSchema } from '../models/User'
import type { Connection } from 'mongoose'
export async function up(connection: Connection) {
const User = connection.model('User', UserSchema)
await User.create([
{
firstName: 'John',
lastName: 'Doe',
},
{
firstName: 'Jane',
lastName: 'Doe',
},
])
}
export async function down(connection: Connection) {
const User = connection.model('User', UserSchema)
await User.deleteMany({ firstName: { $in: ['Jane', 'John'] } }).exec()
}Programmatic mode
Works with any Node.js framework — Express, Fastify, Koa, Hono, etc:
import { Migrator } from 'ts-migrate-mongoose'
const migrator = await Migrator.connect({
uri: 'mongodb://localhost:27017/my-db',
autosync: true,
})
await migrator.run('up') // Run all pending migrations
await migrator.run('down', 'x') // Roll back a specific migration
await migrator.list() // List all migrations and their status
await migrator.create('name') // Create a new migration file
await migrator.prune() // Remove orphaned migrations from DB
await migrator.close() // Close the connectionExpress / Fastify / Koa / Hono
import { Migrator } from 'ts-migrate-mongoose'
// Run before starting your server
const migrator = await Migrator.connect({
uri: process.env.MONGO_URI ?? 'mongodb://localhost:27017/my-db',
autosync: true,
})
await migrator.run('up')
await migrator.close()
// Start your server
app.listen(3000)NestJS (because it's special)
Import MigrationModule from ts-migrate-mongoose/nest:
import { MigrationModule } from 'ts-migrate-mongoose/nest'
@Module({
imports: [
MongooseModule.forRoot(process.env.MONGO_URI),
MigrationModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
uri: config.get<string>('MONGO_URI'),
autosync: true,
}),
}),
],
})
export class AppModule {}Runs all pending up migrations on application bootstrap. For custom control:
MigrationModule.forRoot({
uri: process.env.MONGO_URI,
onBootstrap: async (migrator) => {
await migrator.run('down', 'test')
await migrator.prune()
await migrator.run('up')
},
})See programmatic usage examples for the full API and more examples.
Contributing
Check CONTRIBUTING.md
License
This project is licensed under the MIT License - see the LICENSE file for details
Notes
- Currently, the
-dor--urimust include the database to use for migrations in the uri. - Example:
-d mongodb://localhost:27017/development - If you don't want to pass it every time feel free to use
migrate.tsormigrate.jsonconfig file or an environment variable - Feel Free to check out the
/examplesfolder in the project to get a better idea of usage in Programmatic and CLI mode
Check my other projects
- ts-patch-mongoose - Patch history & events plugin for mongoose
- ts-cache-mongoose - Cache plugin for mongoose Queries and Aggregate (in-memory, redis)
