Database seeding

Database seeding is a way to setup your application with some initial data that is required to run and use the application. For example:

  • Creating a seeder to insert countries, states and cities before deploying and running your application.
  • Or a seeder to insert users inside the database for local development.

In AdonisJS, the seeders are stored inside the database/seeders directory. You can create seeders manually or run the following ace command to create one for you.

node ace make:seeder User

The seeder file is a standard Javascript class as shown in the following example:

database/seeders/UserSeeder.ts
import BaseSeeder from '@ioc:Adonis/Lucid/Seeder'
import User from 'App/Models/User'

export default class UserSeeder extends BaseSeeder {

  public async run () {
    await User.createMany([
      {
        email: '[email protected]',
        password: 'secret',
      },
      {
        email: '[email protected]',
        password: 'supersecret'
      }
    ])
  }

}
  • As you can see, the UserSeeder is a standard Javascript class extending the BaseSeeder.
  • Within the run method, you can execute the database operations.

Running seeders

You can execute all or selected database seeders as shown below:

# runs all
node ace db:seed
# runs database/seeders/UserSeeder
node ace db:seed --files=UserSeeder

There is also an interactive mode to manually select one or more seeders to execute.

node ace db:seed -i

Development only seeders

Lucid allows you to mark your certain seeder files to be available only during the development phase. This ensures that by mistake you are not seeding your production database with dummy data.

import BaseSeeder from '@ioc:Adonis/Lucid/Seeder'

export default class UserSeeder extends BaseSeeder {
  public static developmentOnly = true

  public async run () {
  }

}

The developmentOnly flag ensures that this file is only executed when process.env.NODE_ENV = 'development'.

Idempotent operations

Unlike migrations, there is no tracking system in place for the database seeders. In other words, executing a seeder multiple times will perform the inserts multiple times as well.

Based upon the nature of a seeder, you may or may not want this behavior. For example:

  • It is okay to run a PostSeeder for multiple times and increase the number of posts you have in the database.
  • On the other hand, you would want the CountrySeeder to perform inserts only once. These kind of seeders are idempotent in nature.

Fortunately, Lucid models has inbuilt support for idempotent operations using methods like updateOrCreate or fetchOrCreateMany. Continuing with the CountrySeeder, following is an example of creating countries only once.

import BaseSeeder from '@ioc:Adonis/Lucid/Seeder'
import Country from 'App/Models/Country'

export default class CountrySeeder extends BaseSeeder {

  public async run () {
    const uniqueKey = 'isoCode'

    await Country.updateOrCreateMany(uniqueKey, [
      {
        isoCode: 'IN',
        name: 'India',
      },
      {
        isoCode: 'FR',
        name: 'France',
      },
      {
        isoCode: 'TH',
        name: ' Thailand',
      },
    ])
  }

}

In the above example, the updateOrCreateMany method will look for existing rows inside the database using the isoCode code and only inserts the missing ones and hence running the CountrySeeder for multiple times will not insert duplicate rows.

Learn more about the other idempotent methods here.

Customizing database connection

The db:seed command accepts an optional --connection flag and forwards it to the seeder files as a connection property. From there on, you can use this property to set the appropriate connection during your models interactions. For example:

import BaseSeeder from '@ioc:Adonis/Lucid/Seeder'
import User from 'App/Models/User'

export default class UserSeeder extends BaseSeeder {

  public async run () {
    await User.create({
      email: '[email protected]',
      password: 'secret',
    }, {
      connection: this.connection, // 👈
    })
  }

}

Now you can specify the --connection flag on your db:seed command and the UserSeeder will use it.

node ace db:seed --connection=tenant-1