Database Migrations With Vapor
In this Server-Side Swift tutorial, learn how to perform database migrations with Vapor on your application database – a useful tool for tasks such as creating tables, seeding data, and adding columns. By Heidi Hermann.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Database Migrations With Vapor
25 mins
- Getting Started
- Configuring Your Local PostgreSQL Database Using Docker
- Connecting to Your Database
- Writing Your First Migration
- Migrations in Vapor 4
- Creating a Tools Migration
- Running Your Application
- Implementing FieldKeys
- Rewriting Your First Migration Using FieldKeys
- Replacing Stringly Typed Keys with FieldKeys in Tool and Its Migration
- Reverting Your Migration
- Rerunning Your First Migration
- Adding a Maker to Your Tools
- Adding a New Migration
- Running Your Migration
- Adding a Unique Requirement to Your Tool/Maker Combination
- Building and Running Your App
- Seeding Data Using Migrations
- Where to Go From Here?
All applications are dependent on data. Data is stored in a database with a schema, and you and your customers create and consume it. But when you create a database, you need a way to translate your application models into your database models. In Vapor, this process is called migration. A migration is a set of instructions for how to create or change a model in your database, along with instructions for how to revert those changes. Database migrations with Vapor allow you to add database tables, change columns, and seed data, as well as keep a log of your migrations so you (and your application) know which migrations have or haven’t run.
In this tutorial, you’ll learn how to:
- Create and update a database in Vapor using migrations.
- Create tables, add columns, and more.
- Seed data in your database with a migration.
You may also want to check out the Server-Side Swift with Vapor course to learn more.
- Xcode 11 and Swift 5.4 (or newer versions)
- Docker. If you don’t have Docker yet, visit Docker install for Mac.
- A database client that supports PostgreSQL. This tutorial uses Postico. It’s a free PostgreSQL client that you can download here. However, any database client that supports PostgreSQL will do.
- Xcode 11 and Swift 5.4 (or newer versions)
- Docker. If you don’t have Docker yet, visit Docker install for Mac.
- A database client that supports PostgreSQL. This tutorial uses Postico. It’s a free PostgreSQL client that you can download here. However, any database client that supports PostgreSQL will do.
You may also want to check out the Server-Side Swift with Vapor course to learn more.
Getting Started
Download the starter project by clicking the Download Materials button at the top or bottom of this tutorial. Then, navigate to the starter folder. Open the Vapor app in Xcode by double-clicking Package.swift.
While you wait for the Swift Package Manager (SwiftPM) to resolve dependencies, check out the existing project in /Sources/App/:
Pay attention to the following:
- Configurations: You’ll see two files, configure.swift and Routes.swift. configure.swift includes where you configure your application, and it’s also where you’ll later register your Migrations.
-
Models: This contains the
Tool
database model.
Finally, remember to set the Working Directory inside your build scheme to the project folder.
Configuring Your Local PostgreSQL Database Using Docker
Next, configure your PostgreSQL container. Open your terminal and paste the following command:
$ docker run --name tool_finder -e POSTGRES_DB=vapor_database \
-e POSTGRES_USER=vapor_username -e POSTGRES_PASSWORD=vapor_password \
-p 5432:5432 -d postgres
This command:
- Runs a new container named tool_finder.
- Pulls down the image if it doesn’t exist on your machine already.
- Specifies the database name, vapor_database, username, vapor_username, and password, vapor_password, through environment variables.
- Instructs the container to listen on port
:5432
and exposes the port to your local machine.
5432
, feel free to change the port before you run the command, e.g. -p 54320:5432
. Just remember to update the database configuration in configure.swift. This also applies to --name
, POSTGRES_DB
, POSTGRES_USER
and Connecting to Your Database
The steps to connect to Postgres through your Vapor application are already implemented in configure.swift. So, build and run.
Next, open Postico and click on the New Favorite button in the bottom left corner. It opens a dialog window that allows you to connect to your database. Input the same values you used when you configured your Postgres Docker container.
Once you’ve filled in the form, click Connect. It’ll open the connection to your empty database.
You’ll see two folders:
- pg_catalog: This contains metadata information about the database.
- information_schema: This contains views that return information about the database.
You can read more about pg_catalog and information_schema in the official PostgreSQL documentation.
Writing Your First Migration
When you plan your migrations, there are a few good practices to keep in mind:
- Always do a backup of your database before you run a new set of migrations.
- Be cautious not to make irreversible changes to a live project.
- Consider the order in which you make your migrations.
And, now that you’ve connected your application and Postico to the database, you’re ready to write your first migration.
Migrations in Vapor 4
Fluent, which is Vapor’s ORM library, is responsible for migrations in Vapor. You have to write a migration for each table you want to create and for each change you want to make to your existing tables.
The first time Fluent runs, it creates a special table in the database. Fluent uses this table to track all migrations it has run, and it runs migrations in the order you add them. When your application starts, Fluent checks the list of migrations to run. If it has already run a migration, it’ll move on to the next one. If it hasn’t run the migration before, Fluent executes it.
Fluent will never run migrations more than once. Doing so causes conflicts with the existing data in the database. For example, imagine you have a migration that creates a table for your users. The first time Fluent runs the migration, it creates the table. If it tries to run it again, a table with the name already exists and an error is thrown.
Migration Requirements
To write a migration you need to do the following:
- Import
FluentKit at the beginning of your file.
- Create a
struct
to hold your migration, and give it a relevant and descriptive name. - Make your migration conform to the
Migration
protocol. - Add the required
func prepare(on:) -> EventLoopFuture
. This is where you define the changes you want to make to the database with the migration. - Add the required
func revert(on:) -> EventLoopFuture
. This is where you define how to revert the changes you just made to your database. - Register your migration in your app configuration.
For each field you include in your migration, you have to provide a:
- Field key, which is stringly typed.
- Field type, such as
.string
,.int
,.bool
or.datetime
. - List of field constraints, such as whether or not it's required, if it's an identifier and if it's a foreign key.
Next, you'll learn how to create a Tools migration.