Fluent relations allow you to relate your models in three different ways:

Type Relations
One to One Parent / Child
One to Many Parent / Children
Many to Many Siblings

One to Many

We'll start with one-to-many since it's the easiest type of relation to understand.

Take the following database schema:


id name
<id type> string


id name user_id
<id type> string <id type>


Visit the database preparations guide for more information on how to create schema.

Here each pet has exactly one owner (a user) and each owner can have multiple pets. This is a one-to-many relationship. One owner has many pets.


Use the builder.foreignId() to create foreign ids like user_id. This will automatically create foreign key constraints and follow pre-set key naming conventions.


To access the user's pets, we will use the Children relation.

extension User {
    var pets: Children<User, Pet> {
        return children()

Imagine the children relation as Children<Parent, Child> or Children<From, To>. Here we are relating from the user type to the pet type.

We can now use this relation to get all of the user's pets.

let pets = try user.pets.all() // [Pet]

This will create SQL similar to:

SELECT * FROM `pets` WHERE `user_id` = '...';

Relations work similarly to queries.

let pet = try user.pets.filter("name", "Spud").first()


To access a pet's owner from the pet, we will use the Parent relation.

extension Pet {
    let userId: Identifier


    var owner: Parent<Pet, User> {
        return parent(id: userId)

Imagine the parent relation as Parent<Child, Parent> or Parent<From, To>. Here we are relating from the pet type to the parent type.


Notice the Parent relation requires an identifier to be passed in. Make sure to load this identifier in your model's init(row:) method.

We can now use this relation to get the pet's owner.

let owner = try pet.owner.get() // User?


Adding a parent identifier to the child table can be done using the .parent() method on the schema builder.

try database.create(Pet.self) { builder in

One to One

One-to-one relations work exactly the same as one-to-many relations. You can use the code from the previous example and simply call .first() and all calls from the parent type.

However, you can add a convenience for doing this. Let's assume we wanted to change the previous example from one-to-many to one-to-one.

extension User {
   func pet() throws -> Pet? {
        return try children().first()

Many to Many

Many to many relations require a table in between to store which model is related to which. This table is called a pivot table.

You can use any entity you want as a pivot, but Fluent provides a default one called Pivot.

Take the following schema.


id name
<id type> string


id pet_id toy_id
<id type> <id type> <id type>


id name
<id type> string

Here each pet can own many toys and each toy can belong to many pets. This is a many-to-many relationship.


To represent this many-to-many relationship, we will use the Siblings relation.

extension Pet {
    var toys: Siblings<Pet, Toy, Pivot<Pet, Toy>> {
        return siblings()

Imagine the siblings relations as Siblings<From, To, Through>. Here we are relating from the pet type to the toy type through the pet/toy pivot.


The generic syntax might look a little intimidating at first, but it allows for a very powerful API.

With this relation added on pets, we can fetch a pet's toys.

let toys = pet.toys.all() // [Toy]

The siblings relation works similarly to queries and parent/children relations.


If you are using a Pivot type, you can simply add it to your Droplet's preparation array.

drop.preparations.append(Pivot<Pet, Toy>)

If you are using a Pivot for your "through" model, it will also have methods for adding and removing models from the relation.


To add a new model to the relation, use the .add() method.

try pet.toys.add(toy)


The newly created pivot will be returned.


To remove a model from being related, use the .remove() method.

try pet.toys.remove(toy)

Is Attached

To check if a model is related, use the .isAttached() method.

if try pet.toys.isAttached(to: toy) {
    // it is attached

Custom Through

You can use any entity type as the "through" entity in your siblings relation.

extension User {
    var posts: Siblings<User, Post, Comment> {
        return siblings()

In the above example we are pivoting on the comments entity to retreive all posts the user has commented on.

As long as the "through" entity has a user_id and post_id, the siblings relation will work.


If the Commententity does not conform to PivotProtocol, the add, remove, and isAttached methods will not be available.