Skip to content

04 Relationships

DodaTech 3 min read

In this tutorial, you will learn about Relationships: One. We cover key concepts, practical examples, and best practices to help you master this topic.

GraphQL naturally expresses relationships through nested field types. One-to-one relationships map to a single object field. One-to-many relationships map to a list field. Many-to-many relationships require a join type or an intermediary object.

What You'll Learn

  • Modeling one-to-one relationships with nested object types
  • Modeling one-to-many relationships with list fields
  • Handling many-to-many through join types
  • Bidirectional relationship patterns and nullability decisions

Why It Matters

Properly modeled relationships let clients fetch deeply nested data in a single round trip. Poor relationship design causes excessive database queries, confusing schemas, and broken data integrity.

Real-World Use

GitHub models Repository to Organization as many-to-one (one organization has many repositories). Repository to PullRequest is one-to-many. PullRequest to Review is one-to-many with a join through the Pull Request ID.

flowchart LR
    User[User] -->|1-to-1| Profile[Profile]
    User -->|1-to-many| Post[Post]
    Post -->|many-to-many| Category[Category]
    Category -->|many-to-many| Post

Teacher Mindset

Design relationships from both sides of the association. If you query a user and need their posts, posts must be a field on User. If you query a post and need its author, author must be a field on Post.

Code Examples

# Example 1: One-to-one relationship
type User {
  id: ID!
  name: String!
  profile: Profile!
}

type Profile {
  id: ID!
  bio: String!
  avatarUrl: String
  user: User!
}
# Example 2: One-to-many relationship
type Author {
  id: ID!
  name: String!
  books: [Book!]!
}

type Book {
  id: ID!
  title: String!
  author: Author!
}
# Example 3: Many-to-many through a join type
type Student {
  id: ID!
  name: String!
  enrollments: [Enrollment!]!
}

type Course {
  id: ID!
  title: String!
  enrollments: [Enrollment!]!
}

type Enrollment {
  id: ID!
  student: Student!
  course: Course!
  enrolledAt: Date!
  grade: String
}

Common Mistakes

  • Forgetting to add the reverse relationship on both sides of a bidirectional association
  • Using non-null on both sides of a one-to-one when one side might not exist
  • Creating circular queries that go infinitely deep without implementing pagination
  • Representing many-to-many as lists on both sides without an intermediary
  • Ignoring the N+1 Problem caused by resolving relationship fields individually

Practice

  1. Model an Employee-Department schema with one-to-many from Department to Employee.
  2. Add a one-to-one Profile relationship to the Employee type.
  3. Design a many-to-many relationship between Movie and Actor with a Role type.
  4. Implement bidirectional relationships on both sides.
  5. Challenge: Model a social media schema with User, Post, Comment, and Like (where Like is a join between User and Post).

FAQ

How do I avoid circular references in GraphQL?

GraphQL tolerates circular type references. The runtime resolves fields lazily. Use pagination on list fields to prevent infinite nesting in queries.

Should every relationship be bidirectional?

No. Only add reverse relationships when clients need to traverse from the other side. Unnecessary relationships bloat the schema.

How do I handle optional relationships?

Make the field nullable (profile: Profile) instead of non-null (profile: Profile!). This allows the relationship to be absent.

What is a join type in GraphQL?

A join type models the many-to-many relationship as an explicit object with its own fields, like Enrollment connecting Student and Course.

How do I paginate one-to-many relationships?

Replace the list field with a connection type (posts: PostConnection) following the Relay Connection specification.

Mini Project

Add relationships to your e-commerce schema: one-to-one between User and Cart, one-to-many between Category and Product, and many-to-many between Product and Order through an OrderItem join type with quantity and price fields.

What's Next

Next, you will learn how to design queries that fetch data from your GraphQL API, including arguments, aliases, fragments, and variables.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro