How to define Sequelize associations using migrations
The Sequelize CLI is pretty great at generating model and migration files, but not at adding associations with other models.
Unfortunately there is not much (clear) documentation about adding associations in migration files — so whilst figuring this out myself I decided to write down to basic examples for the 4 types of associations to save others the time.
I suggest creating all models first, and then adding associations in a separate migration file. This prevents errors surrounding models that do not exist yet. For me, this has proven to be the easiest way to get the database up to an initial state.
Example order of files:
Create all the models and their migrations using
To check if the models are created correctly I suggest running
sequelize db:migrate and seeing if there any errors.
Note: if you get an error saying the ‘Dialect needs to be explicitly supplied as of v4.0.0’, export the NODE_ENV of your configuration first, e.g.
If there are no errors, we can move on to the next step.
Depending on the size of your project you can split up the associations for each model, or have all of them in one file. When starting a project, I like to do them all in one file, but it’s up to personal preference and how many associations each model has.
First, let’s create the migration file where we will be doing all the associations:
sequelize migration:generate --name add-associations.
According to the documentation a belongsTo relation ‘adds a foreign key and singular association mixins to the source’.
In our example an
Order belongs to a
Customer. In this case, the source is
Order so we will need to add a
CustomerId key to the
Note: I’m using UUID’s for my ids. If you use the standard integers change the type to
DataTypes.INTEGER, remove the
defaultValue line and change
In our migration file we will need to add a column called
CustomerId. This can be done using the
queryInterface.addColumn method. We also need to provide a
down function that will return the database to the state before the migration.
A couple of things to notice here:
- Table names are plural and the reference key is exactly like the key used when defining the models (most of the time it will be
- The foreign key is capitalized.
- We’re also defining
onDelete. The default is
CASCADEfor update and
SET NULLfor delete for belongsTo, hasOne and hasMany. BelongsToMany associations will have
CASCADEas default for both update and delete.
Note: if you’re using integers instead of UUID’s use
Save and run
sequelize db:migrate. If all is well, let’s run
sequelize db:migrate:undo to check if the undo function works too.
When defining a hasOne relation ‘the foreign key is added on the target’.
In our example
Payment has one
Order. Order is the target so we will need to add a
PaymentId key to the
Let’s add our migration of the hasOne key. We’re appending that migration to add-associations.js so the complete file will look like this:
Notice that we are chaining the
queryInterface methods because they return Promises.
sequelize db:migrate again. If there are no errors run
sequelize db:migrate:undo to check if our
down function also works.
A hasMany association “creates a 1:m association between the source and the provided target. The foreign key is added on the target.”
In our example an
Order has many
Product s. Let’s update our
order.js model file.
Now we need to add the
OrderId column to the
Products table in the migration file:
Pretty straight-forward :)
This is where it gets slightly more complicated. A belongsToMany relation creates a n:m association through a join table.
In our example a
Product belongs to many
Tag s and vice versa. Here are the model definitions:
Notice the following:
- we are defining
through: 'ProductTags'. This defines that we are storing the n:m association in the
- we are defining the belongsToMany association in both models using the same
To keep things more concise I’ll create a new migration file for this association by running
sequelize migration:generate --name associate-product-tag .
queryInterface.addColumn we now need to use
This table doesn’t need an
id key. Please note that
TagId are both primary keys. For the
down function we’re just dropping the table again.
sequelize db:migrate again and see if it works. Don’t forget to test the
down function by running
That’s it! I hope these basic examples help and save you some time. If you have any questions don’t hesitate to ask.