Migrations
Migrating the schema of a database as features are built is an imporant part of Evolutionary Database Design. Platter's branching model was built with this incremental design process in mind, and makes database migrations a less error-prone process.
While the Postgres Client does not have any built-in schema migration methods, the schema can be altered directly with query. In many cases, this will be sufficient. For those that would like a more systematic migration experience, we recommend migrate, an abstract migration framework for Node.
This guide will show you how to use migrate and @platter/migrate-store to incrementally change the schema of your Postgres databases. For this example, you will learn how to build a schema for a basic blog API that returns collections of posts and authors.
Prerequisites#
A Postgres database. See the "Setting Up Postgres" section of the Quick Start for more information. Like the Quick Start, this guide will use a database named my-new-database.
Creating Migrations#
Install
migrateas adevDependencywith:migrateuses timestamped.jsfiles in amigrationsdirectory to schedule migrations. To generate your first migration, run:...which will create a
./migrations/1613143187252-add-posts.jsfile on your behalf (example timestamp). Your project structure will look like this afterwards:Migration files export
upanddownmethods that correspond to applying and reverting migrations, respectively. Replace the contents of your*-add-posts.jsfile with the following:migrations/$TIMESTAMP-add-posts.jsFrom here, migrate your schema with:
...and reverted those changes with:
Tracking Migrations#
By default, migrate only stores migrations locally. This approach does not work well with branching databases, as the state of a database will often be different from the state of those migration-tracking files. Instead, migrations can be tracked in the database by implementing a custom store.
Platter has created a custom store implementation that uses Postgres Clients to track migrations separately in each branch of a database.
Install
@platter/migrate-storeas adevDependencywith:@platter/migrate-storeexpectsPLATTER_API_KEYandPLATTER_POSTGRES_CLIENTenvironment variables on invocation, andmigrateexpects the store implementation to be provided through a--storeoption. Putting that together, migrations can now be performed like so:
Transactional Migrations#
Now that each branch of a database tracks its own set of migrations, it's time to add another migration that includes more complex logic that needs to be performed in multiple steps. This is a perfect use-case for a Transaction.
postsshould haveauthors, of course. Create a migration forauthorswith:Replace the contents of your new
*-add-authors.jsmigration file with the following:migrations/$TIMESTAMP-add-authors.jsRun the
upmigration command once more, and you'll notice that only the second migration was run. This will be true for anyone that clones your project or branches this database in the future!
Deployment#
To see how migrations interact with popular build systems and branch deploys, take a look at the guide for Netlify Functions.