Welcome to this hands-on tutorial on creating and managing up and down seeders using Sequelize! Imagine you are setting up a new garden where you want to plant specific flowers (data) in well-defined beds (tables). Seeder files provide the instructions on what to plant, and just like a gardener, you might sometimes need to remove or replant your seeds if things go wrong.
In this lesson, you’ll learn how to define the "up" and "down" functions in seeder files, the differences between using the queryInterface methods and using Model.bulkCreate, and how to run and undo seeders via the command-line interface.
To get started, you need to generate a seeder file using the Sequelize CLI. This file will contain two main functions: an up function to insert seed data and a down function to remove that data.
Run this command in your terminal:
npx sequelize seed:generate --name <name_of_seed>
Replace <name_of_seed> with a descriptive name, such as demo-users. The command creates a seeder file
with a timestamp prefix (e.g., 20230412123456-demo-users.js) in the seeders folder.
Open the generated seeder file. You will see two callback functions:
Here is an example of what the file might look like:
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
/**
* Add seed commands here.
*
* Example:
* await queryInterface.bulkInsert('People', [{
* name: 'John Doe',
* isBetaMember: false,
* createdAt: new Date(),
* updatedAt: new Date()
* }], {});
*/
},
down: async (queryInterface, Sequelize) => {
/**
* Add commands to revert seed here.
*
* Example:
* await queryInterface.bulkDelete('People', null, {});
*/
}
};
In this file, queryInterface.bulkInsert is used to insert an array of objects representing your seed data,
and queryInterface.bulkDelete is used to remove that data. Notice that when using bulkInsert, you must manually
add createdAt and updatedAt timestamps if your table requires them.
While queryInterface.bulkInsert is useful, it does not run model-level validations and does not automatically set timestamps.
For example, if your model expects a boolean value for isBetaMember but receives a string, bulkInsert will not catch the error.
// This will NOT throw an error even if validations exist in the model:
await queryInterface.bulkInsert('People', [
{
name: 'John Doe',
isBetaMember: "yes", // should be boolean
createdAt: new Date(),
updatedAt: new Date()
}
], {});
To overcome these limitations, the recommended approach is to use Model.bulkCreate instead.
This method runs all model-level validations and automatically handles timestamps if configured.
Think of it as using a smart planter that checks the quality of your seeds before planting them.
Here’s how you can do it:
// Import the model (e.g., Person) from your models folder
const { Person } = require('../db/models');
// Use bulkCreate to insert seed data with validations
await Person.bulkCreate([
{
name: 'John Doe',
isBetaMember: false
}
], { validate: true });
With validate: true, Sequelize will run all validations defined in the model, ensuring data integrity.
Creating a seeder file doesn’t automatically insert data into your database. Once you have defined your seed data in the up function, you need to execute the seed command:
npx dotenv sequelize db:seed:all
This command runs all your seed files and populates your database. If you need to run a specific seed file, you can specify it:
npx dotenv sequelize db:seed --seed <name_of_seeder>
Just as migrations have a down function to undo changes, seeders have a down function to remove the inserted data. In your seeder file, you might have:
'use strict';
const { Person } = require('../db/models');
module.exports = {
up: async (queryInterface, Sequelize) => {
await Person.bulkCreate([
{
name: 'John Doe',
isBetaMember: false
}
], { validate: true });
},
down: async (queryInterface, Sequelize) => {
await queryInterface.bulkDelete('People', {
name: 'John Doe',
isBetaMember: false
});
}
};
To undo all seeds, run:
npx dotenv sequelize db:seed:undo:all
Or to undo a specific seed:
npx dotenv sequelize db:seed:undo --seed <name_of_seeder>
Think of your database as a newly tilled field and seeder files as instructions for planting crops.
The up function is when you plant your seeds (insert data), and the down function is like pulling the crops out
if they don’t grow correctly or need to be replaced. Using Model.bulkCreate instead of the more basic method
ensures that each seed is checked for quality before being planted, resulting in a healthy, robust field.
up function in a seeder file inserts data using methods like queryInterface.bulkInsert or
the preferred Model.bulkCreate (with validations).
down function undoes the seed by removing data, typically using queryInterface.bulkDelete.
npx dotenv sequelize db:seed:all to run seeds, and npx dotenv sequelize db:seed:undo:all
to revert them.
In this tutorial, you learned how to create up and down seeders in Sequelize to populate and depopulate your database. Seeders are essential for testing and initializing your database with consistent, quality data. By using Model.bulkCreate, you can ensure that the data adheres to your model's validations, while the down function provides a safe way to revert your seed data if needed.
With this knowledge, you can confidently manage your seed data, keeping your database robust and reliable throughout your application’s development lifecycle. Happy seeding!