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.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Creating a Tools Migration

In Xcode, add a new folder named Migrations inside your App folder.

Next, add a new Swift file named 21-05-31_Tool+Create.swift to hold your migration defining the entity's table.

For example, you could use 20210123_Tool+AddUpdatedAt if you needed to add an updated_at field to an existing table for the Tool model.

  • Prefix the file name with the date it was created in year/month/day format. This allows you to maintain an overview of the proper order your migrations were created in and the order in which they should be executed.
  • Use a descriptive name for the migration explaining what the migration is doing to the model.
When naming your migration files, it's good practice to:
  • Prefix the file name with the date it was created in year/month/day format. This allows you to maintain an overview of the proper order your migrations were created in and the order in which they should be executed.
  • Use a descriptive name for the migration explaining what the migration is doing to the model.

For example, you could use 20210123_Tool+AddUpdatedAt if you needed to add an updated_at field to an existing table for the Tool model.

Replace the new file's contents with:

// 1
import FluentKit

// 2
extension Tool {
  struct Create: Migration {
    // 3
    func prepare(on database: Database) -> EventLoopFuture<Void> {
      return database
        .schema("tools") // 4
        .id() // 5
        .field("name", .string, .required) // 6
        .field("created_at", .datetime) // 7
        .field("updated_at", .datetime)
        .create() // 8
    }

    // 9
    func revert(on database: Database) -> EventLoopFuture<Void> {
      return database.schema("tools").delete()
    }
  }
}

Here you:

  1. Import FluentKit to expose Migration.
  2. Extend your Tool database model and create a struct called Create and make it conform to the Migration protocol. The migration is a nested type to keep migrations organized with their model.
  3. Add the required method func prepare(on:) -> EventLoopFuture.
  4. Provide the schema of the database model.
  5. Create the id for the model.
  6. Add a field for the name of the Tool.
  7. Create the two timestamps for ToolcreatedAt and updatedAt.
  8. Create the table.
  9. Add the required method, func revert(on:) -> EventLoopFuture. Inside, call the .delete() method on the Tool table.
  1. The field names are in snake_case, even though the properties in the application are in camelCase. This is a convention from PostgreSQL, since, by default, it's case insensitive in regard to keys.
  2. The .id() builder method is only available if your ID type is UUID. If you're using an int, you'll have to define the property yourself using .field("id", .int, .identifier(auto: true)).
Note:
  1. The field names are in snake_case, even though the properties in the application are in camelCase. This is a convention from PostgreSQL, since, by default, it's case insensitive in regard to keys.
  2. The .id() builder method is only available if your ID type is UUID. If you're using an int, you'll have to define the property yourself using .field("id", .int, .identifier(auto: true)).

Next, open /Configurations/configure.swift and register your migration with the application by replacing the comment on line 47 with the following:

app.migrations.add(Tool.Create())

Next time you run your application with migrate enabled, your model will be created in your database.

Running Your Application

Now, open your build scheme and add migrate under Arguments Passed On Launch.

Xcode build scheme with migrate added to the list of arguments passed on launch.

Xcode build scheme with migrate enabled.

Xcode build scheme with migrate added to the list of arguments passed on launch.

Then, run your application.

Output dialog when running your migrations in Vapor 4.

Output dialog for the create Tool migration.

Output dialog when running your migrations in Vapor 4.

This will prompt a dialog in your output window telling you which migrations will be run and asking you if you're sure you want to go ahead with them.

Type y and press enter.

Wait for the success command to print, along with a message that the command ended. Then, open the build schema and remove the migrate argument.

You can explicitly run them from your terminal using vapor run migrate, or from inside Xcode like you just did. In both cases, you'll receive the command prompt, but you can also pass -y as an argument to skip the prompt.

You can also run the migrations automatically by either adding try app.autoMigrate().wait() inside your configure.swift, or passing the --auto-migrate flag when you run your application.

Note:
There are a number of options for you to run your migrations.

You can explicitly run them from your terminal using vapor run migrate, or from inside Xcode like you just did. In both cases, you'll receive the command prompt, but you can also pass -y as an argument to skip the prompt.

You can also run the migrations automatically by either adding try app.autoMigrate().wait() inside your configure.swift, or passing the --auto-migrate flag when you run your application.

In the next section, you'll view your database.

Viewing Your Database With Postico

Now, access your database with Postico.

Postico overview of migrated tables.

View of migrated models in Postico.

Postico overview of migrated tables.

You can see that Tool/code> has been added to the database, along with another table named _fluent_migrations.

First, open _fluent_migrations.

_fluent_migrations table visualized in Postico. One migration is registered in the table.

Overview of the migrations logged in the _fluent_migrations table.

_fluent_migrations table visualized in Postico. One migration is registered in the table.

Vapor autogenerates this table and holds a registry of all the migrations you've run.

Each migration has a unique identifier, the name you gave it, a batch number and timestamps for creation and update.

Since it was your first migration, the batch number is 1. Each time you run a new migration, the batch number will increase by one.

Next, open the tools table, and in the bottom-left corner, choose to view the Structure.

Structure of the tools table in the database. It has four fields with keys and types matching those you defined in your migration.

Structure of the tools table in the database.

Structure of the tools table in the database. It has four fields with keys and types matching those you defined in your migration.

Here, you see that the table has four columns that match the ones you defined in your migration:

  1. id: Of type UUID, and with the primary key constraint enabled.
  2. name: Of type TEXT, and with NOT NULL enabled.
  3. created_at: Of type TIMESTAMPZ (timestamp with time zone).
  4. updated_at: Of type TIMESTAMPZ.

Moving on, you'll learn about FieldKeys.