Four kinds, declared on the models after both exist.| Declaration | Where the key lives |
|---|
A.hasOne(B) | on B |
A.hasMany(B) | on B |
A.belongsTo(B) | on A |
A.belongsToMany(B, { through }) | in the join table |
Declare both sides. hasMany alone gives you user.posts; adding belongsTo
gives you post.author as well, and lets you filter posts by their author.[!IMPORTANT]
Declare the associations before prorm.connect() / sync(). The
REFERENCES clause is written when the table is created, and a model defined
on an already-open connection has its table created immediately — before
hasMany / belongsTo have run.
Each side also gets helper methods on its rows:Loading them#
One query per level, not one per user — the parents, then every child in one
IN (…):Nest as deep as you need:Filtering by the other table#
An include with a where is required by default, so required: true here only
says it out loud. Prorm finds the matching posts first and pages the users
that own them:With required: false, every user comes back, and only the published posts
are attached (an empty array for the rest):Many to many#
The join table is created by sync() if it does not exist:Rows get addTag, addTags, removeTag, setTags, getTags, countTags
and hasTag. addTag inserts a junction row every time, so guard against
linking the same pair twice:Referential actions#
sync() puts the actions on the foreign key. On SQLite:[!IMPORTANT]
When both sides declare the key (User.hasMany(Post) and
Post.belongsTo(User)), the association declared first sets the reference,
so put the actions there (or on both). Before 4.9.2 the actions never reached
the table; see
Foreign keys and constraints
for tables created by an older release.
Next#
Modified at 2026-10-04 00:40:16