Data Migrations
Learn how to update your database data through migrations.
On occasion, Novu may introduce features that require changes to the database schema or data. This usually happens when a feature has a hard dependency on some data being available on a database entity. You can use migrations to make these changes to your database.
How to Run Novu Migrations (Manual Process)
Novu does not automatically run database migrations when deploying new versions. If you're self-hosting or managing deployments outside a CI/CD pipeline, follow these steps to safely run migrations against your MongoDB database.
For Novu Cloud, the Novu team have a custom deployment service that runs migrations on AWS and is triggered by our team. By policy any changes are backward compatible and non schema migrations is needed for any deployment. So any migration can be run after the service was already deployed unless specified otherwise. Those migrations are usually for cleanup purposes, and schema alignment.
For Novu Self-Hosting, each migration can be run locally against your Mongodb using known connection strings that have
credentials. Your connection may require further access via a tunnel. A script has been added at the bottom that help
manages the complexity of versions across connections strings. Manually add and run run-migrations.sh
script from
apps/api
folder.
Overview
- Migrations are manual.
- They must be run from an environment that has access to the migration scripts.
- There is no practical way to run those from within the docker container at the moment becuase the migrations scripts are not shipped with the images
- Requires valid MongoDB credentials and network access.
- Typically run during deployment of new application versions.
- Novu does not use a versioning or idempotent migration strategy. See Versioning Note below.
- Migrations once added to source code do not change (by policy)
- Refer to the table of releases to know which to run when
- There is a shell script at the end that you can use to ease the burden ( see run-migrations.sh)
- Success of this process requires cloning the git repository and setting up the projects from source before starting migrations
- Success may also require the Redis instance to be running during execution for some migrations (here's the kicker, these are running locally otherwise you would need (potentially) another tunnel through to the remote version [TODO: confirm side effects (April, 2025)])
- Warning: some migrations do not exit fully when run in the bash script ( eg < 0.19.0 ) and require Ctrl-C to finish and continue
- Warning: not all migrations are fully documented in the release notes for each release
- Warning: migrations are dependent on the underlying code (eg repositories) and matches the version of the code against the migration at the right point in time is crucial and each version also requires the correct version of
node
andpnpm
Migration Release Map
This table maps each migration script to the likely Novu release version, based on the date the script was added and the closest following release tag.
Release Version | Release Date | Migrations Introduced |
---|---|---|
v0.17.2 | 2023-08-13 | novu-integrations (Integration Store) |
v0.18.0 | 2023-08-14 | changes-migration (Change Promotion) encrypt-credentials (Secure Credentials) expire-at (Database TTL) fcm-credentials (Secure Credentials) in-app-integration (In-App Integration) normalize-users-email (Organization Invite Fix) secure-to-boolean (Secure Flag Fix) seen-read-support (Seen/Read Support) |
v0.21.0 | 2023-09-01 | integration-scheme-update (Multi-Provider) layout-identifier-update (Add layout identifier) |
v0.23.0 | 2024-02-02 | encrypt-api-keys (API keys encryption) |
v0.24.0 | 2024-03-06 | normalize-message-template-cta-action (Normalize CTA action) topic-subscriber-normalize (Normalize topic-subscriber links) |
v2.0.0 | 2024-10-07 | subscribers (Subscriber record adjustments) |
v2.0.1 | 2024-11-11 | preference-centralization (Preference model centralization) — ensure this is done before v2.1 as repository access has been removed |
(future release) | sometime 2025 | deleteLogs (Cleanup deleted logs) |
Historical releases
Version | Feature | Migration Path(s) |
---|---|---|
v0.23 | API keys encryption | ./encrypt-api-keys/encrypt-api-keys-migration.ts |
v0.18 | Multi-Provider | ./integration-scheme-update/add-primary-priority-migration.ts ./integration-scheme-update/add-integration-identifier-migration.ts |
Integration Store | ./novu-integrations/novu-integrations.migration.ts | |
v0.16 | In-App Integration | ./in-app-integration/in-app-integration.migration.ts |
Secure Flag Fix | ./secure-to-boolean/secure-to-boolean-migration.ts | |
v0.15 | Database TTL | ./expire-at/expire-at.migration.ts |
v0.12 | Organization Invite Fix | ./normalize-users-email/normalize-users-email.migration.ts |
v0.9 | Seen/Read Support | ./seen-read-support/seen-read-support.migration.ts |
v0.8 | Secure Credentials | ./fcm-credentials/fcm-credentials-migration.ts ./encrypt-credentials/encrypt-credentials-migration.ts |
v0.4 | Change Promotion | ./changes-migration.ts |
Step-by-Step Instructions
Runtime prerequisites
node
npm
pnpm
npx
- MacOS (or linux)
- tunnel (optional
ssh
)
Some migration scripts (like in-app-integration
) require access to Redis during execution. If Redis is not running,
you will encounter ECONNREFUSED 127.0.0.1:6379
. The problem here is that remote environments have their own Redis and
currently the assumption is that migrations should only affect the MongoDB collection. To fix this start Redis locally (
or launch a Docker container: docker run -p 6379:6379 redis
)
1. Clone the Novu Repository
Ensure you’re using the same version as the one you’re deploying:
Warning: migrations are dependent on the underlying code (eg repositories)
- match the version of the code against the migration at the right point in time
- each version often requires the correct version of
node
andpnpm
as per thepackage.json
Notes:
- Getting the code the run at a checked out version can be tricky
- If you want to know which tags are available:
git tag
- Some migrations may fail because they rely on the underlying code rather than direct mongo queries
- Migrations are located in:
apps/api/migrations/
- Checkout by tag stops accidentally running too many migrations that would normally be managed by migrations runner ( see migration versioning )
2. Connect to Your MongoDB Database
If your database is not directly accessible, you may need to tunnel:
Have your:
- MongoDB connection string
- Username and password (if required)
3. Run the Migration Script
use the script
run-migrations.sh
below for all the following steps
Configure access to the correct database:
Some notes:
- under the hood of the migration script
npx ts-node --transpile-only ./apps/api/migrations/<script-name>.ts
- some migrations require REDIS (ensure already running)
- some migrations require NEW_RELIC (so turn off)
- Run each script only once. Monitor logs or database changes for success.
5. Repeat for Each Relevant Migration
Use a migration release map to determine which scripts are required for your upgrade.
Post-Migration Validation
After completing migrations:
- Verify new fields/collections are present
- Check logs for errors
- Confirm application starts and behaves as expected
Migration Versioning and Idempotency
Novu does not implement a versioning system or record migration history in the database. This means:
- Migrations must be manually tracked.
- There is no built-in idempotency for running the migration, so running a script twice may cause duplicate data or errors (but by policy the underlying code does its best)
- It is your responsibility to ensure each script runs only once and in the correct order.
What Is an Idempotent Migration?
An idempotent migration can be safely run multiple times without changing the outcome after the first execution. This is typically achieved through:
- Tracking applied migrations in a collection (e.g.,
migrations
). - Guard clauses in code to check if a change has already been made.
Note:
- there are libraries that support idempotent Mongo migrations in TypeScript
- if you want to introduce versioned/idempotent migrations in your own deployment process, consider
migrate-mongo
ormongodb-migrations
Tips
- Always back up your database before running migrations.
- Consider scripting or CI/CD automation for repeatability.
- Dockerized deployments do not auto-run migrations—there is no explicit configuration to turn this on either.
- You could implement your own migrations versioning on top
Run Migrations Script
Use this shell to ease the burden, ensure that it is executable. Instructions are in the script comments.
Reference for Generating Table
The migration-to-release mapping is done by comparing the migration creation date to the next release tag chronologically.
If multiple migrations appear before a release, they’re grouped under that version.