Migrations

    You will need Sequelize CLI. The CLI ships support for migrations and project bootstrapping.

    Let's start with installing CLI, you can find instructions . Most preferred way is installing locally like this

    Bootstrapping

    To create an empty project you will need to execute command

    1. $ node_modules/.bin/sequelize init

    This will create following folders

    • config, contains config file, which tells CLI how to connect with database
    • models, contains all models for your project
    • migrations, contains all migration files
    • seeders, contains all seed files

    Configuration

    Before continuing further we will need to tell CLI how to connect to database. To do that let's open default config file config/config.json. It looks something like this

    1. {
    2. "development": {
    3. "username": "root",
    4. "password": null,
    5. "database": "database_development",
    6. "host": "127.0.0.1",
    7. "dialect": "mysql"
    8. },
    9. "test": {
    10. "username": "root",
    11. "password": null,
    12. "database": "database_test",
    13. "host": "127.0.0.1",
    14. "dialect": "mysql"
    15. },
    16. "production": {
    17. "username": "root",
    18. "password": null,
    19. "database": "database_test",
    20. "host": "127.0.0.1",
    21. "dialect": "mysql"
    22. }
    23. }

    Now edit this file and set correct database credentials and dialect.

    Note:If your database doesn't exists yet, you can just call db:create command. With proper access it will create that database for you.

    Creating first Model (and Migration)

    Once you have properly configured CLI config file you are ready to create your first migration. It's as simple as executing a simple command.

    We will use model:generate command. This command requires two options

    • name, Name of the model
    • attributes, List of model attributes

    Let's create a model named User.

    1. $ node_modules/.bin/sequelize model:generate --name User --attributes firstName:string,lastName:string,email:string

    This will do following

    • Create a model file user in models folder
    • Create a migration file with name like XXXXXXXXXXXXXX-create-user.js in migrations folder

    Note:Sequelize will only use Model files, it's the table representation. On the other hand, the migration file is a change in that model or more specifically that table, used by CLI. Treat migrations like a commit or a log for some change in database.

    Running Migrations

    Until this step, we haven't inserted anything into the database. We have just created required model and migration files for our first model User. Now to actually create that table in database you need to run db:migrate command.

    1. $ node_modules/.bin/sequelize db:migrate

    This command will execute these steps:

    • Will ensure a table called SequelizeMeta in database. This table is used to record which migrations have run on the current database
    • Start looking for any migration files which haven't run yet. This is possible by checking SequelizeMeta table. In this case it will run XXXXXXXXXXXXXX-create-user.js migration, which we created in last step.
    • Creates a table called Users with all columns as specified in its migration file.

    Undoing Migrations

    Now our table has been created and saved in database. With migration you can revert to old state by just running a command.

    You can use db:migrate:undo, this command will revert most recent migration.

    1. $ node_modules/.bin/sequelize db:migrate:undo

    You can revert back to initial state by undoing all migrations with db:migrate:undo:all command. You can also revert back to a specific migration by passing its name in —to option.

    1. $ node_modules/.bin/sequelize db:migrate:undo:all --to XXXXXXXXXXXXXX-create-posts.js

    Creating First Seed

    To manage all data migrations you can use seeders. Seed files are some change in data that can be used to populate database table with sample data or test data.

    Let's create a seed file which will add a demo user to our User table.

    1. $ node_modules/.bin/sequelize seed:generate --name demo-user

    This command will create a seed file in seeders folder. File name will look something like XXXXXXXXXXXXXX-demo-user.js. It follows the same up / down semantics as the migration files.

    Now we should edit this file to insert demo user to User table.

    In last step you have create a seed file. It's still not committed to database. To do that we need to run a simple command.

    1. $ node_modules/.bin/sequelize db:seed:all

    This will execute that seed file and you will have a demo user inserted into User table.

    Note:Seeders execution is not stored anywhere unlike migrations, which use the SequelizeMeta table. If you wish to override this please read Storage section

    Undoing Seeds

    Seeders can be undone if they are using any storage. There are two commands available for that:

    If you wish to undo most recent seed

    1. node_modules/.bin/sequelize db:seed:undo

    If you wish to undo all seeds

    1. node_modules/.bin/sequelize db:seed:undo:all

    Migration Skeleton

    The following skeleton shows a typical migration file.

    1. module.exports = {
    2. up: (queryInterface, Sequelize) => {
    3. // logic for transforming into the new state
    4. },
    5. down: (queryInterface, Sequelize) => {
    6. // logic for reverting the changes
    7. }
    8. }

    The passed queryInterface object can be used to modify the database. The Sequelize object stores the available data types such as STRING or INTEGER. Function up or down should return a Promise. Let's look at an example:

    1. module.exports = {
    2. return queryInterface.createTable('Person', {
    3. name: Sequelize.STRING,
    4. isBetaMember: {
    5. type: Sequelize.BOOLEAN,
    6. defaultValue: false,
    7. allowNull: false
    8. }
    9. });
    10. },
    11. down: (queryInterface, Sequelize) => {
    12. return queryInterface.dropTable('Person');
    13. }
    14. }

    The .sequelizerc File

    This is a special configuration file. It lets you specify various options that you would usually pass as arguments to CLI. Some scenarios where you can use it.

    • You want to override default path to migrations, models, seeders or folder.
    • You want to rename config.json to something else like database.json

    And a whole lot more. Let's see how you can use this file for custom configuration.

    For starters, let's create an empty file in root directory of your project.

    1. $ touch .sequelizerc

    Now let's work with an example config.

    1. const path = require('path');
    2. module.exports = {
    3. 'config': path.resolve('config', 'database.json'),
    4. 'models-path': path.resolve('db', 'models'),
    5. 'seeders-path': path.resolve('db', 'seeders'),
    6. 'migrations-path': path.resolve('db', 'migrations')
    7. }

    With this config you are telling CLI to

    • Use config/database.json file for config settings
    • Use db/models as models folder
    • Use db/seeders as seeders folder
    • Use db/migrations as migrations folder

    Dynamic Configuration

    Sequelize CLI can read from both JSON and JS files. This can be setup with .sequelizerc file. Let see how

    First you need to create a .sequelizerc file in root folder of your project. This file should override config path to a JS file. Like this

    Now Sequelize CLI will load config/config.js for getting configuration options. Since this is a JS file you can have any code executed and export final dynamic configuration file.

    An example of config/config.js file

    1. const fs = require('fs');
    2. module.exports = {
    3. development: {
    4. username: 'database_dev',
    5. password: 'database_dev',
    6. database: 'database_dev',
    7. host: '127.0.0.1',
    8. dialect: 'mysql'
    9. },
    10. test: {
    11. username: 'database_test',
    12. password: null,
    13. database: 'database_test',
    14. host: '127.0.0.1',
    15. dialect: 'mysql'
    16. },
    17. production: {
    18. username: process.env.DB_USERNAME,
    19. password: process.env.DB_PASSWORD,
    20. database: process.env.DB_NAME,
    21. host: process.env.DB_HOSTNAME,
    22. dialect: 'mysql',
    23. dialectOptions: {
    24. ssl: {
    25. ca: fs.readFileSync(__dirname + '/mysql-ca-master.crt')
    26. }
    27. }
    28. }
    29. };

    Using Environment Variables

    With CLI you can directly access the environment variables inside the config/config.js. You can use .sequelizerc to tell CLI to use config/config.js for configuration. This is explained in last section.

    Then you can just expose file with proper environment variables.

    1. module.exports = {
    2. development: {
    3. username: 'database_dev',
    4. password: 'database_dev',
    5. database: 'database_dev',
    6. host: '127.0.0.1',
    7. dialect: 'mysql'
    8. },
    9. test: {
    10. username: process.env.CI_DB_USERNAME,
    11. password: process.env.CI_DB_PASSWORD,
    12. database: process.env.CI_DB_NAME,
    13. host: '127.0.0.1',
    14. dialect: 'mysql'
    15. },
    16. production: {
    17. username: process.env.PROD_DB_USERNAME,
    18. password: process.env.PROD_DB_PASSWORD,
    19. database: process.env.PROD_DB_NAME,
    20. dialect: 'mysql'
    21. }

    Sometime you want to specify a dialectOption, if it's a general config you can just add it in config/config.json. Sometime you want to execute some code to get dialectOptions, you should use dynamic config file for those cases.

    1. {
    2. "production": {
    3. "dialect":"mysql",
    4. "dialectOptions": {
    5. "bigNumberStrings": true
    6. }
    7. }

    Production Usages

    Some tips around using CLI and migration setup in production environment.

    1) Use environment variables for config settings. This is better achieved with dynamic configuration. A sample production safe configuration may look like.

    1. const fs = require('fs');
    2. module.exports = {
    3. development: {
    4. username: 'database_dev',
    5. password: 'database_dev',
    6. database: 'database_dev',
    7. host: '127.0.0.1',
    8. dialect: 'mysql'
    9. },
    10. test: {
    11. username: 'database_test',
    12. password: null,
    13. database: 'database_test',
    14. host: '127.0.0.1',
    15. dialect: 'mysql'
    16. },
    17. production: {
    18. username: process.env.DB_USERNAME,
    19. password: process.env.DB_PASSWORD,
    20. database: process.env.DB_NAME,
    21. host: process.env.DB_HOSTNAME,
    22. dialect: 'mysql',
    23. dialectOptions: {
    24. ssl: {
    25. ca: fs.readFileSync(__dirname + '/mysql-ca-master.crt')
    26. }
    27. }
    28. }
    29. };

    Our goal is to use environment variables for various database secrets and not accidentally check them in to source control.

    Storage

    There are three types of storage that you can use: sequelize, json, and none.

    • sequelize : stores migrations and seeds in a table on the sequelize database
    • json : stores migrations and seeds on a json file
    • none : does not store any migration/seed

    Migration Storage

    By default the CLI will create a table in your database called SequelizeMeta containing an entryfor each executed migration. To change this behavior, there are three options you can add to theconfiguration file. Using migrationStorage, you can choose the type of storage to be used formigrations. If you choose json, you can specify the path of the file using migrationStoragePathor the CLI will write to the file sequelize-meta.json. If you want to keep the information in thedatabase, using sequelize, but want to use a different table, you can change the table name usingmigrationStorageTableName.

    1. {
    2. "development": {
    3. "username": "root",
    4. "password": null,
    5. "database": "database_development",
    6. "host": "127.0.0.1",
    7. "dialect": "mysql",
    8. // Use a different storage type. Default: sequelize
    9. "migrationStorage": "json",
    10. // Use a different file name. Default: sequelize-meta.json
    11. "migrationStoragePath": "sequelizeMeta.json",
    12. // Use a different table name. Default: SequelizeMeta
    13. "migrationStorageTableName": "sequelize_meta"
    14. }
    15. }

    Note:The none storage is not recommended as a migration storage. If you decide to use it, beaware of the implications of having no record of what migrations did or didn't run.

    Seed Storage

    By default the CLI will not save any seed that is executed. If you choose to change this behavior (!),you can use seederStorage in the configuration file to change the storage type. If you choose json,you can specify the path of the file using seederStoragePath or the CLI will write to the filesequelize-data.json. If you want to keep the information in the database, using sequelize, you canspecify the table name using seederStorageTableName, or it will default to SequelizeData.

    1. {
    2. "development": {
    3. "username": "root",
    4. "password": null,
    5. "database": "database_development",
    6. "host": "127.0.0.1",
    7. "dialect": "mysql",
    8. // Use a different storage. Default: none
    9. "seederStorage": "json",
    10. // Use a different file name. Default: sequelize-data.json
    11. "seederStoragePath": "sequelizeData.json",
    12. // Use a different table name. Default: SequelizeData
    13. "seederStorageTableName": "sequelize_data"
    14. }
    15. }

    Configuration Connection String

    As an alternative to the —config option with configuration files defining your database, you canuse the —url option to pass in a connection string. For example:

    1. $ node_modules/.bin/sequelize db:migrate --url 'mysql://root:password@mysql_host.com/database_name'

    Connecting over SSL

    Ensure ssl is specified in both dialectOptions and in the base config.

    Programmatic use

    Sequelize has a sister library for programmatically handling execution and logging of migration tasks.