You are looking at the old Apostrophe 0.5 documentation. It is deprecated for new projects. Check out the latest version!

Database Migrations

← Previous: Adding nunjucks filters and functions

Sometimes you'll want to change the way you store data on your site and you'll need a reliable way to apply that change to existing data. Database migrations are a great way to solve this problem. Apostrophe uses database migrations internally to upgrade existing sites when we make schema changes.

You can add your own database migrations to your project. For instance, you might do this in afterInit in your app.js file:

site.apos.addMigration('paintTheFences', function(callback) {
  return site.apos.forEachPage({ type: 'fence', title: /gray/i }, {}, function(page, callback) {
    page.title = page.title.replace(/gray/gi, 'white');
    return site.apos.pages.update({ _id: page._id }, page, callback);
  }, callback);

This migration will now run in the order it was registered. Core Apostrophe migrations run first, followed by those registered by each module in your project, followed by those registered in afterInit.

There are many helper methods defined in migrationTools.js, such as the apos.forEachPage module used here, that can help you when you need to iterate over everything in the site. Also keep in mind that apos.pages is the aposPages MongoDB collection object.

Your migration must:

  • Have a unique name (the first argument to addMigration). Use a short prefix such as a module name or project name to prevent conflict with similar migrations added by unrelated modules.

  • Tolerate being run more than once on the same database. If you cannot guarantee a "safe" migration, write a separate task instead and use it only once.

  • Tolerate being run on a brand-new site.

  • Do something asynchronous before invoking its callback, except in the event of an error. If everything is great and you have no async work to do, use return setImmediate(callback).

Yes, there is a cache that remembers which migrations have been run, but you must treat it as a performance optimization only and assume that your migration might get run again.

Next: Accessing the database directly →