✨ Basics
Migrations

The Migrations

Migrations in AdonisJS

Migrations are used to manage your database schema. They allow you to define the structure of your database tables and make changes to them over time in a consistent and controlled way.

Creating a Migration

1. Using the command line

You can create a migration using the command line.

node ace make:migration users

This will create a new file in the database/migrations folder.

2. Then, create a migration manually

You can create a migration manually by creating a new file in the database/migrations folder.

database/migrations/xxxx_xx_xx_create_users_table.ts
import { BaseSchema } from "@adonisjs/lucid/schema";
 
export default class extends BaseSchema {
  protected tableName = 'users'
 
  async up() {
    this.schema.createTable(this.tableName, (table) => {
      table.string('id').primary().unique()
      table.string('name')
      table.string('surname')
      table.string('email').notNullable().unique()
      table.string('password')
      table.string('role').notNullable()
      table.string('provider').notNullable()
 
      table.timestamp('created_at').defaultTo(this.now())
      table.timestamp('updated_at').defaultTo(this.now())
    })
  }
 
  async down() {
    this.schema.dropTable(this.tableName)
  }
}

Migration Properties

  • tableName: Specifies the name of the table being created or modified.
  • up(): Defines the schema changes to be applied when the migration is run.
  • down(): Defines the schema changes to be reverted when the migration is rolled back.

Example User Migration

The users table is defined with the following columns:

  • id: A primary and unique string identifier.
  • name: A string for the user's name.
  • surname: A string for the user's surname.
  • email: A not nullable and unique string for the user's email.
  • password: A string for the user's password.
  • role: A not nullable string for the user's role.
  • provider: A not nullable string for the authentication provider.
  • created_at: A timestamp for when the user was created, defaulting to the current time.
  • updated_at: A timestamp for when the user was last updated, defaulting to the current time.

Creating the Users Table

database/migrations/xxxx_xx_xx_create_users_table.ts
import { BaseSchema } from "@adonisjs/lucid/schema";
 
export default class extends BaseSchema {
  protected tableName = 'users'
 
  async up() {
    this.schema.createTable(this.tableName, (table) => {
      table.string('id').primary().unique()
      table.string('name')
      table.string('surname')
      table.string('email').notNullable().unique()
      table.string('password')
      table.string('role').notNullable()
      table.string('provider').notNullable()
 
      table.timestamp('created_at').defaultTo(this.now())
      table.timestamp('updated_at').defaultTo(this.now())
    })
  }
 
  async down() {
    this.schema.dropTable(this.tableName)
  }
}

Example Address Migration with Relationship

The addresses table is defined with the following columns and a foreign key relationship to the users table:

  • id: A primary auto-increment integer identifier.
  • user_id: A string that references the id column in the users table.
  • post_code: A not nullable integer for the post code.
  • address: A not nullable string for the address.
  • city: A not nullable string for the city.
  • country: A not nullable string for the country.
  • created_at: A timestamp for when the address was created, defaulting to the current time.
  • updated_at: A timestamp for when the address was last updated, defaulting to the current time.

Creating the Addresses Table

database/migrations/xxxx_xx_xx_create_addresses_table.ts
import { BaseSchema } from "@adonisjs/lucid/schema";
 
export default class extends BaseSchema {
  protected tableName = 'addresses'
 
  async up() {
    this.schema.createTable(this.tableName, (table) => {
      table.increments('id')
      table.string('user_id').notNullable().references('id').inTable('users')
      table.integer('post_code').notNullable()
      table.string('address').notNullable()
      table.string('city').notNullable()
      table.string('country').notNullable()
 
      table.timestamp('created_at').defaultTo(this.now())
      table.timestamp('updated_at').defaultTo(this.now())
    })
  }
 
  async down() {
    this.schema.dropTable(this.tableName)
  }
}

Relationships Explained

In the above example, the addresses table has a foreign key relationship with the users table. This relationship is defined by the user_id column in the addresses table, which references the id column in the users table.

Defining the Foreign Key

table.string('user_id').notNullable().references('id').inTable('users')

This line ensures that each address is associated with a user, enforcing referential integrity. If a user is deleted, the related addresses can also be handled accordingly (e.g., deleted or set to null).

It should be used when you create in the table that has belongsTo relationship with another table.

See more

Using migrations ensures that your database schema evolves in a controlled and consistent manner, allowing you to define, modify, and rollback changes as needed.