Using Fluent and Persisting Models in Vapor

The Fluent ORM lets you use any number of database engines in your Vapor app. Learn how to persist your models in your server side Swift apps using Vapor! By Tim Condon.

Leave a rating/review
Download materials
Save for later

Fluent is Vapor’s ORM or object relational mapping tool. It’s an abstraction layer between the Vapor application and the database, and it’s designed to make working with databases easier. Using an ORM such as Fluent has a number of benefits.

The biggest benefit is you don’t have to use the database directly! When you interact directly with a database, you write database queries as strings. These aren’t type-safe and can be painful to use from Swift.

Fluent benefits you by allowing you to use any of a number of database engines, even in the same app. Finally, you don’t need to know how to write queries since you can interact with your models in a “Swifty” way.

Models are the Swift representation of your data and are used throughout Fluent. Models are the objects, such as user profiles, you save and access in your database. Fluent returns and uses type-safe models when interacting with the database, giving you compile-time safety.

In this tutorial, you’ll learn how to use Fluent to save data in Vapor applications.

Note: This tutorial follows on from the setup in the “Getting Started with Server-side Swift using Vapor” tutorial. If you haven’t followed those steps, please visit that tutorial now and return here when you’re done.

Getting Started

Start by creating a new project, using the Vapor Toolbox. In Terminal, enter the following commands:

cd ~/vapor
vapor new TILApp

The first command takes you into a directory called vapor inside your home directory and assumes that you completed the steps in the “Getting Started with Server-side Swift using Vapor” tutorial.

The second command creates a new Vapor 3 project called TILApp using the default template.

New TILApp Project

The template provides examples files for models and controllers. You’ll build your own so delete the examples. In Terminal, enter:

cd TILApp
rm -rf Sources/App/Models/*
rm -rf Sources/App/Controllers/*

Since Xcode projects are discardable when using Vapor — they’re entirely optional — it’s best practice to create your project files outside of Xcode. This lets Swift Package Manager, which is used by Vapor Toolbox, ensure that they link to the correct targets. Create a file to hold the Acronym model:

touch Sources/App/Models/Acronym.swift

This command creates a Swift file inside the App module’s Models directory called Acronym.swift. Now generate your Xcode project:

vapor xcode -y

This will open the project in Xcode.

Open configure.swift in the App folder, find the Configure migrations group and delete the following line:

migrations.add(model: Todo.self, database: .sqlite)

Next, open routes.swift and delete the following lines:

// Example of configuring a controller
let todoController = TodoController()
router.get("todos", use: todoController.index)"todos", use: todoController.create)
router.delete("todos", Todo.parameter, use: todoController.delete)

This removes the remaining references to the template’s example model and controller.

Creating the Model

Open Acronym.swift and add the following to create the basic model for the acronym:

import Vapor
import FluentSQLite

final class Acronym: Codable {
  var id: Int?
  var short: String
  var long: String

  init(short: String, long: String) {
    self.short = short
    self.long = long

The model contains two String properties to hold the acronym and its definition. It also contains an optional id property that stores the ID of the model, if one has been set.

All Fluent models must conform to Codable. It’s also good practice to mark classes final, where possible, as it provides a performance benefit. The ID is set by the database when the acronym is saved.

Next make Acronym conform to Fluent’s Model. Add the following at the end of the file:

extension Acronym: Model {
  // 1
  typealias Database = SQLiteDatabase
  // 2
  typealias ID = Int
  // 3
  public static var idKey: IDKey = \

Here’s what this does:

  1. Tells Fluent what database to use for this model. The template is already configured to use SQLite.
  2. Tells Fluent what type the ID is.
  3. Tells Fluent the key path of the model’s ID property.

But this code can be improved further with SQLiteModel. Replace:

extension Acronym: Model {
  typealias Database = SQLiteDatabase
  typealias ID = Int
  public static var idKey: IDKey = \

with the following:

extension Acronym: SQLiteModel {}

The Fluent packages provide Model helper protocols for each database provider so you don’t have to specify the database or ID types, or the key. The SQLiteModel protocol must have an ID of type Int? called id, but there are SQLiteUUIDModel and SQLiteStringModel protocols for models with IDs of type UUID or String. If you want to customize the ID property name, you must conform to the standard Model protocol.

Creating a Table for the Model

To save the model in the database, you must create a table for it. Fluent does this with a migration. Migrations allow you to make reliable, testable, reproducible changes to your database. They are commonly used to create a database schema, or table description, for your models. They are also used to seed data into your database or make changes to your models after they’ve been saved.

Add the following at the end of Acronym.swift to make the model conform to Migration:

extension Acronym: Migration {}

That is all you need to do! Fluent infers the schema for your model thanks to Codable. For basic models you can use the default implementations for Migration. If you need to change your model later or do more complex things, such as marking a property as unique, you may need to implement your own migrations.

Now that Acronym conforms to Migration, you can tell Fluent to create the table when the application starts. Open configure.swift and find the section labeled // Configure migrations. Add the following before services.register(migrations):

migrations.add(model: Acronym.self, database: .sqlite)

Fluent supports mixing multiple databases in a single application, so you specify which database holds each model. Migrations only run once; once they have run in a database, they are never executed again. It’s important to remember this as Fluent won’t attempt to recreate a table if you change the model.

Set the active scheme to Run with My Mac as the destination. Build and run. Check the console and see that the migrations have run. You should see something similar to the console output below:

Migration complete