Skip to main content

Documentation Index

Fetch the complete documentation index at: https://archie.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

A relationship connects two tables with a foreign key. When you add a relationship field, Archie creates the foreign key in the database, generates the inverse field on the other table automatically, and exposes both sides as nested fields in the GraphQL API. This page covers the cardinalities you can model, how to set up many-to-many, and how the relationships look in the auto-generated APIs.

Cardinality

CardinalityWhat it meansReal-world example
One-to-OneRecord A ↔ exactly one Record B (and vice versa).A User has one Profile.
One-to-ManyRecord A ↔ many Record Bs, but each B belongs to exactly one A.An Author has many Books; each Book has one Author.
Many-to-ManyRecord A ↔ many Record Bs and Record B ↔ many Record As.A Student takes many Courses; a Course has many Students.
The Relationship field type supports One-to-One and One-to-Many directly. Many-to-many is modeled with a join table — see below.

One-to-many

The most common cardinality. The “many” side holds the foreign key. Example: an author has many books. The books table holds an author_id relationship field pointing to authors. When you add the author relationship on books with cardinality One-to-Many (one author, many books), Archie automatically:
  • Creates the author_id foreign key column on books.
  • Generates a books nested field on Author in the GraphQL schema.
  • Generates an author nested field on Book in the GraphQL schema.
query {
  author(id: "...") {
    name
    books {
      title
    }
  }
}

query {
  book(id: "...") {
    title
    author {
      name
    }
  }
}

One-to-one

A user has exactly one profile, and a profile belongs to exactly one user. Add a relationship field on the side that owns the foreign key (typically profile.user_id), pick One-to-One as the cardinality, and Archie enforces the uniqueness so that no two profiles can point to the same user.
query {
  user(id: "...") {
    profile {
      avatar_url
    }
  }
}

Many-to-many

For many-to-many, create a join table that holds two relationship fields — one to each side. Example: students enrolling in courses.
  1. Create a students table.
  2. Create a courses table.
  3. Create a student_courses join table with two fields:
    • student — relationship to students, cardinality One-to-Many.
    • course — relationship to courses, cardinality One-to-Many.
  4. Optionally, add a unique index across (student, course) to prevent duplicate enrollments.
The auto-generated GraphQL API now lets you traverse from a student to all their courses (via the join table) and from a course to all its students.
query {
  student(id: "...") {
    name
    student_courses {
      course {
        title
      }
    }
  }
}
The join table itself is a first-class table — you can attach extra fields to it (for example enrolled_at, grade) to record per-link metadata.

Mandatory vs. optional relationships

Toggle Mandatory on the relationship field to require a related record. A non-mandatory relationship can be null — for example, a comment can optionally belong to a parent_comment for threaded replies.

Cascade behavior on delete

By default, the database prevents you from deleting a record that other records reference — this protects against orphaned data. If you have an author with books, deleting the author fails until the books are reassigned or deleted. Common alternatives:
BehaviorWhat it doesWhen to use it
Restrict (default)Block the delete while related records exist.Default. Forces you to handle related data explicitly.
CascadeDelete related records too.Strong ownership — deleting a post should delete its comments.
Set nullClear the reference; keep the related records.Loose ownership — deleting a category shouldn’t delete its posts, just unlink them.
Configure cascade behavior through the relationship field’s configuration panel.

How it appears in the API

Every relationship is exposed in the auto-generated GraphQL API as a nested field on each side. Filtering, sorting, and pagination on related collections is supported. See the GraphQL API Explorer to inspect the exact shape generated for your tables. The REST API exposes related records via standard endpoint patterns and query parameters.

Permissions

Reading or writing a relationship requires permissions on both sides. A user can only see related records on a table they’re allowed to read. Configure this in Role-Based Access.

FAQ

Many-to-many is always implemented under the hood as a join table with two one-to-many relationships. Modeling it explicitly gives you a place to attach metadata to each link (for example, when a student enrolled, what grade they got). The Data Model exposes that pattern directly rather than hiding it.
No. The relationship field is the foreign key. Adding it creates the column, the database constraint, and the inverse query in GraphQL all at once.
The inverse field updates to match the new name. Any client code that referenced the old nested field name needs to be updated.
Yes. For example, a messages table could have both a sender and a recipient relationship pointing to users. Pick distinct field names so the two relationships are clearly distinguishable in the GraphQL schema.
When you delete a post with comments configured to cascade, the database deletes the post and every comment that points to it as part of the same transaction. Choose cascade only when child records have no meaning without the parent.