Versioning & Migrations
Historically, zero-downtime migrations are painful and costly. For example, assume you'd like to rename a column without downtime that is accessed by a web service. In a traditional database setup, before $PLACEHOLDER_NAME$, you'd follow these steps:
- Add the new column with the new column name.
- Deploy a new version of the web service that reads from the old column, but writes to both the old and the new column.
- Copy all data from the old column to the new column.
- Deploy a new version of the web service that only uses the new column.
- Drop the old column.
This is a lot of work, as it requires implementing a temporary version of the web service that supports both old and new versions of the database schema. There is also a lot of room for manual user error, and it's impossible to automate this process. When things break, it is also hard to revert.
For those reasons, most teams just avoid database changes wherever possible, leading to technical debt. This is why $PLACEHOLDER_NAME$ uses an entirely different approach to migrations.
Our approach
Instead of making the web service support multiple versions of the database, $PLACEHOLDER_NAME$ databases support multiple versions of the web service. This lets $PLACEHOLDER_NAME$ automatically do the hardest part of the migration for you:
- Create a new version of the database resource that updates the column name.
- Both versions of the database are now up and serving; behind the scenes, there is only one (hidden) column, and both the old and new columns are simply references to its data.
- Deploy a new version of the web service that only uses the new column.
- Finalize the migration (in the Dashboard or the CLI), making the new version of the database resource the default version.
- This deletes the old version, and replaces the new column with the actual (previously hidden) data column.
This can not just be applied to database tables and columns, in fact, it is available on every resource as a
version
property. It also makes reverting back to old versions as trivial as changing a line of code.Versioning resources
The
versioned
helper function lets you define a resource that has multiple versions:There are multiple syntaxes that you can use as you wish:
It is very important to never change or delete old versions of a resource in the source code, or an error will be thrown. From $PLACEHOLDER_NAME$'s perspective, the code to port data from the old version is still required because there could still be deployments that have not been updated yet (for example in a gradual rollout or AB test). For more information on why non-destructive configuration changes like this are not allowed, see the Configuration page.
Finalizing migrations
As long as a migration is not finalized,
... (insert description how to do it in dashboard, and CLI)
It may be tempting to keep around old versions of a resource forever, never finalizing a migration. Indeed, you could do this, and your app would behave correctly. However, supporting multiple versions comes at a performance cost. We therefore recommend finalizing migrations as soon as you are confident you can do it safely.
Reverting updates
As long as you don't finalize a migration, no data is ever lost. Even after ...
...
Why a version number bump?
Changes that don't require migrations
...
Development mode
...