Getting Started With Vapor 3 Part 4:

Using PostgreSQL

In Part 3 we started working with a Park model and defined two endpoints that returned information about parks. We used an in-memory array to hold Park instances. In this tutorial we'll set up a PostgreSQL database to work with Vapor so we can start persisting model objects between sessions and define the basic CRUD endpoints for Park.

Installing Postgres

We'll use Homebrew, a popular package manager for macOS, to install postgres. To install Homebrew, open a new Terminal window and enter the following:

/usr/bin/ruby -e "$(curl -fsSL"

Next we'll install brew services. In order to work with PostgreSQL locally, we'll need to start a PostgreSQL server, and brew services makes it easier to start and stop the server.

brew tap homebrew/services

Now let's use Homebrew to install Postgres:

brew install postgresql

To start a PostgreSQL server, run:

brew services start postgresql

Now run brew services list. You should see that the status of postgresql is "started".

To create our NationalParks database, run createdb NationalParks. To work with the database locally, run psql NationalParks.

At this point, the database is empty, but we can run a few commands to get basic information about it. Try each of the following:

SELECT current_database();
SELECT version();

The first should return the name of the database, NationalParks. The second should return the Postgres version and information about your macOS setup. The third lists relations in the database. Currently it should say "No relations found."

Run \q to quit psql.

Vapor Setup

We're now ready to add Postgres to our Vapor project. Replace Package.swift with the following:

// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "NationalParks",
    dependencies: [
        .package(url: "", from: "3.0.0"),
        .package(url: "", from: "1.0.0")
    targets: [
        .target(name: "App", dependencies: ["Vapor", "FluentPostgreSQL"]),
        .target(name: "Run", dependencies: ["App"]),
        .testTarget(name: "AppTests", dependencies: ["App"])

Back in Terminal, run vapor update -y. Your Xcode project should automatically open when the update is finished.

Next we need to configure our Vapor project to use Postgres. Replace configure.swift with the following:

import Vapor
import FluentPostgreSQL

public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {
    let router = EngineRouter.default()
    try routes(router)
    services.register(router, as: Router.self)

    try services.register(FluentPostgreSQLProvider())
    let psqlConfiguration = PostgreSQLDatabaseConfig(
        hostname: "",
        port: 5432,
        username: "[MAC_USERNAME]",
        database: "NationalParks",
        password: nil

    var middlewares = MiddlewareConfig()

Make sure to replace the value for username with your own Mac username.

Now let's see if our setup is working. To do that we'll run the same SELECT version(); query we ran earlier in psql in a Vapor route. Replace routes.swift with the following:

import Vapor
import FluentPostgreSQL

public func routes(_ router: Router) throws {
    router.get("version", use: databaseVersion)

private func databaseVersion(_ request: Request) throws -> Future<String> {
    return request.withPooledConnection(to: .psql) { (connection: PostgreSQLDatabase.Connection) in
        return connection.query("SELECT version();").map(to: String.self) { rows in
            return try rows[0].firstValue(name: "version")?.decode(String.self) ?? ""

In Vapor 3, requests have convenience methods to get a database connection. We use that here to establish a connection to our Postgres database, then execute our version query and map the result to a String. If you run this and go to /version in your browser, you should see the same output you saw earlier in psql.

In this part, we installed PostgreSQL, created a database, and configured Vapor to use it. Next we'll add a table for our Park model and define a basic controller.