VibORM
Relations

Relations Overview

Define relationships between models — oneToOne, oneToMany, manyToOne, and manyToMany

Chainable API

VibORM uses a chainable API for defining relations:

s.manyToOne(() => targetModel).fields("fk").references("id")

The thunk () => targetModel comes first to handle circular references between models, then configuration methods are chained.

Relation Types

RelationDescriptionExample
s.oneToOne()One record relates to one otherUser → Profile
s.oneToMany()One record relates to manyUser → Posts
s.manyToOne()Many records relate to onePost → Author
s.manyToMany()Many relate to manyPost ↔ Tags

Quick Example

import { s } from "viborm";

const user = s.model({
  id: s.string().id().ulid(),
  email: s.string().unique(),
  profile: s.oneToOne(() => profile).optional(),
  posts: s.oneToMany(() => post),
});

const profile = s.model({
  id: s.string().id().ulid(),
  bio: s.string(),
  userId: s.string().unique(),
  user: s.oneToOne(() => user)
    .fields("userId")
    .references("id"),
});

const post = s.model({
  id: s.string().id().ulid(),
  title: s.string(),
  authorId: s.string(),
  author: s.manyToOne(() => user)
    .fields("authorId")
    .references("id"),
  tags: s.manyToMany(() => tag),
});

const tag = s.model({
  id: s.string().id().ulid(),
  name: s.string().unique(),
  posts: s.manyToMany(() => post),
});

Methods by Relation Type

ToOne Relations (oneToOne, manyToOne)

s.manyToOne(() => target)
  .fields("authorId")       // FK field on current model
  .references("id")         // Referenced field on target model
  .optional()               // Mark as optional (FK can be null)
  .onDelete("cascade")      // Referential action on delete
  .onUpdate("cascade")      // Referential action on update
  .name("author")           // Custom relation name

ToMany Relations (oneToMany)

s.oneToMany(() => target)
  .name("posts")            // Custom relation name (only method needed)

The FK configuration is done on the manyToOne side, not here.

ManyToMany Relations

s.manyToMany(() => target)
  .through("post_tags")     // Junction table name
  .A("postId")              // Source FK in junction table
  .B("tagId")               // Target FK in junction table
  .onDelete("cascade")      // Referential action (applies to both FKs)
  .onUpdate("cascade")      // Referential action (applies to both FKs)
  .name("tags")             // Custom relation name

Referential Actions

ActionDescription
cascadeDelete/update related records
setNullSet FK to NULL (requires nullable FK)
restrictPrevent delete/update if related records exist
noActionDatabase default behavior

Class Structure

VibORM uses standalone classes for different relation types:

ToOneRelation       → oneToOne, manyToOne
ToManyRelation      → oneToMany
ManyToManyRelation  → manyToMany

Each class only exposes methods relevant to that relation type.

Pages

On this page