Data Access

Relational Data

Read and write related data across collections.

Read a To-One Relation

Fetch an article with its author by requesting fields from the related collection. Use dot notation in REST or nested arrays in the SDK.

const article = await client.Articles.readOne({
  key: 1,
  fields: ['id', 'title', { author: ['name', 'email'] }],
});

Read a To-Many Relation

Fetch an author with all their articles. The related items are returned as an array.

const author = await client.Authors.readOne({
  key: 1,
  fields: ['id', 'name', { articles: ['title', 'status'] }],
});

Filter, Sort, and Paginate Nested Relations

Apply filters, sorting, and pagination to related items. In REST, use deep with underscore-prefixed keys. In the SDK, use expanded field selection syntax — there is no top-level deep parameter.

const author = await client.Authors.readOne({
  key: 1,
  fields: [
    'id',
    'name',
    {
      articles: {
        fields: ['title', 'status'],
        filter: { status: { _eq: 'published' } },
        sort: [{ created_at: { direction: 'desc' } }],
        limit: 5,
      },
    },
  ],
});
REST deep parameters use underscore prefixes: _filter, _sort, _limit, _offset. The SDK extracts these automatically from the expanded field selection syntax.

For more on field selection patterns, see Field Selection.


Nested Relational Operations

When creating or updating items, you can modify related items in the same request using nested relational operations. This avoids multiple round-trips and ensures all changes happen atomically within a single transaction.

There are five operations available:

OperationDescriptionAvailable In
_connectLink an existing item by its primary keyCreate, Update
_createCreate a new related item inlineCreate, Update
_disconnectUnlink a related item without deleting itUpdate
_updateModify a related item's fields in placeUpdate
_deletePermanently remove a related itemUpdate

In create context, only _connect and _create are available — you cannot disconnect, update, or delete relations that don't exist yet. In update context, all five operations are available and can be combined in a single request.

Operations are expressed as entries in an array on the relation field. They execute in the order they appear in the array, giving you precise control over the sequence of changes.


Use _connect to link an existing item by its primary key. Available in both create and update contexts.

To-One

To-one _connect uses key (singular object). In create context, the relation field is a singular object. In update context, it is wrapped in an array.

// Create context — singular object
const article = await client.Articles.createOne({
  data: {
    title: 'New Article',
    author: {
      _connect: { key: { id: 7 } },
    },
  },
  fields: ['id', 'title', { author: ['id', 'name'] }],
});

// Update context — array-wrapped
const article = await client.Articles.updateOne({
  key: 1,
  data: {
    author: [{ _connect: { key: { id: 7 } } }],
  },
  fields: ['id', 'title', { author: ['id', 'name'] }],
});

To-Many

To-many _connect uses keys (plural, array of key objects).

const article = await client.Articles.updateOne({
  key: 1,
  data: {
    tags: [
      { _connect: { keys: [{ id: 1 }, { id: 3 }, { id: 5 }] } },
    ],
  },
  fields: ['id', { tags: { fields: ['id', 'name'] } }],
});
To-one _connect uses key (singular object). To-many _connect uses keys (plural, array of objects).
If the key does not exist, the operation fails with a 404 and the entire transaction rolls back.

Use _create to create a new related item and link it in one operation. Available in both create and update contexts.

To-One

To-one _create takes a singular data object.

const article = await client.Articles.createOne({
  data: {
    title: 'Getting Started',
    author: {
      _create: { data: { name: 'Jane Doe', email: 'jane@example.com' } },
    },
  },
  fields: ['id', 'title', { author: ['id', 'name'] }],
});

To-Many

To-many _create takes an array of objects in data.

// Create context — create parent with new related items
const author = await client.Authors.createOne({
  data: {
    name: 'New Author',
    articles: [
      {
        _create: {
          data: [
            { title: 'First Article' },
            { title: 'Second Article' },
          ],
        },
      },
    ],
  },
  fields: ['id', 'name', { articles: { fields: ['title'] } }],
});

// Update context — add new related items to existing parent
const article = await client.Articles.updateOne({
  key: 1,
  data: {
    comments: [
      { _create: { data: [{ body: 'Great post!' }, { body: 'Thanks for sharing!' }] } },
    ],
  },
  fields: ['id', { comments: { fields: ['id', 'body'] } }],
});
To-one _create takes a singular data object. To-many _create takes an array of objects.

Use _disconnect to remove a link without deleting the related item. Only available in update context.

To-One

To-one _disconnect takes an empty object {} — there is only one link to remove.

const article = await client.Articles.updateOne({
  key: 1,
  data: {
    author: [{ _disconnect: {} }],
  },
  fields: ['id', 'title'],
});
Use _disconnect instead of _delete when you want to keep the related item. For example, unassigning an author from an article without deleting the author.

To-Many

To-many _disconnect takes a filter object. Use an empty filter {} to disconnect all.

// Disconnect items matching a filter
const article = await client.Articles.updateOne({
  key: 1,
  data: {
    comments: [
      { _disconnect: { filter: { status: { _eq: 'draft' } } } },
    ],
  },
  fields: ['id', { comments: { fields: ['id', 'body', 'status'] } }],
});

// Disconnect all
const article = await client.Articles.updateOne({
  key: 1,
  data: {
    tags: [{ _disconnect: { filter: {} } }],
  },
  fields: ['id'],
});

Use _update to modify a related item's fields without changing the link itself. Only available in update context. Takes data (the fields to change) and an optional filter to target specific items.

To-One

const article = await client.Articles.updateOne({
  key: 1,
  data: {
    author: [{ _update: { data: { name: 'Jane Smith' } } }],
  },
  fields: ['id', { author: ['id', 'name'] }],
});

To-Many

Pass both filter and data. Omit filter to update all related items.

// Update matching items by filter
const article = await client.Articles.updateOne({
  key: 1,
  data: {
    comments: [
      { _update: { filter: { status: { _eq: 'pending' } }, data: { status: 'approved' } } },
    ],
  },
  fields: ['id', { comments: { fields: ['id', 'body', 'status'] } }],
});

// Update all (omit filter)
const article = await client.Articles.updateOne({
  key: 1,
  data: {
    comments: [
      { _update: { data: { reviewed: true } } },
    ],
  },
  fields: ['id'],
});

Use _delete to permanently remove related items from the database. Only available in update context. Takes an optional filter to target specific items.

To-One

const article = await client.Articles.updateOne({
  key: 1,
  data: {
    author: [{ _delete: { filter: {} } }],
  },
  fields: ['id', 'title'],
});

To-Many

const article = await client.Articles.updateOne({
  key: 1,
  data: {
    comments: [
      { _delete: { filter: { flagged: { _eq: true } } } },
    ],
  },
  fields: ['id', { comments: { fields: ['id', 'body'] } }],
});
_delete permanently removes items from the database. Use _disconnect to remove only the link.

Combine Multiple Operations

Multiple relational operations on the same field are expressed as separate entries in the array. Operations process in the order they appear.

const article = await client.Articles.updateOne({
  key: 1,
  data: {
    tags: [
      // 1. Remove links to specific tags
      { _disconnect: { filter: { name: { _starts_with: 'draft' } } } },
      // 2. Delete tags that are obsolete
      { _delete: { filter: { id: { _in: [10, 11] } } } },
      // 3. Update remaining tags
      { _update: { data: { reviewed: true } } },
      // 4. Create a new tag
      { _create: { data: [{ name: 'graphql' }] } },
      // 5. Connect existing tags
      { _connect: { keys: [{ id: 7 }] } },
    ],
  },
  fields: ['id', { tags: { fields: ['id', 'name'] } }],
});
Operations are processed in the order they appear in the array. Place disconnects and deletes before connects and creates to avoid conflicts like duplicate links or constraint violations.

Nest Across Multiple Levels

Relational operations compose at any depth. Create an article with a new author and comments, where comments themselves link to existing authors.

const article = await client.Articles.createOne({
  data: {
    title: 'New Article',
    author: { _create: { data: { name: 'Jane' } } },
    comments: [
      {
        _create: {
          data: [
            { body: 'First!', author: { _connect: { key: { id: 1 } } } },
          ],
        },
      },
    ],
  },
  fields: ['id', 'title', { author: ['id', 'name'] }, { comments: { fields: ['id', 'body', { author: ['id', 'name'] }] } }],
});

Context Differences (Create vs Update)

The available operations and syntax differ between create and update contexts.

Create Context

Only _connect and _create are available. You cannot disconnect, update, or delete relations that do not exist yet.

  • To-one: the relation field is a singular object containing one operation
  • To-many: the relation field is an array where each element is one operation
Create context
const article = await client.Articles.createOne({
  data: {
    title: 'New Article',
    // To-one: singular object
    author: { _connect: { key: { id: 1 } } },
    // To-many: array of operations
    comments: [
      { _create: { data: [{ body: 'Welcome!' }] } },
      { _connect: { keys: [{ id: 100 }, { id: 101 }] } },
    ],
  },
  fields: ['id'],
});

Update Context

All five operations are available: _connect, _create, _disconnect, _update, _delete.

Both to-one and to-many relations use arrays in update context. This enables combining multiple operations on the same field — for example, disconnecting the current author then connecting a new one:

Update context
const article = await client.Articles.updateOne({
  key: 1,
  data: {
    // To-one: array wrapping in update context
    author: [
      { _disconnect: {} },
      { _connect: { key: { id: 5 } } },
    ],
    // To-many: also array wrapping
    comments: [
      { _disconnect: { filter: { status: { _eq: 'spam' } } } },
      { _delete: { filter: { flagged: { _eq: true } } } },
      { _update: { data: { status: 'reviewed' }, filter: { status: { _eq: 'pending' } } } },
      { _create: { data: [{ body: 'Pinned comment' }] } },
    ],
  },
  fields: ['id'],
});
In update context, both to-one and to-many relations are wrapped in arrays. This differs from create context where to-one is a singular object.

Quick Reference

OperationTo-One (Create)To-One (Update)To-Many (Create)To-Many (Update)
Create{ _create: { data: { ... } } }[{ _create: { data: { ... } } }][{ _create: { data: [{ ... }] } }][{ _create: { data: [{ ... }] } }]
Connect{ _connect: { key: { id } } }[{ _connect: { key: { id } } }][{ _connect: { keys: [{ id }] } }][{ _connect: { keys: [{ id }] } }]
DisconnectN/A[{ _disconnect: {} }]N/A[{ _disconnect: { filter: { ... } } }]
UpdateN/A[{ _update: { data: { ... } } }]N/A[{ _update: { filter: { ... }, data: { ... } } }]
DeleteN/A[{ _delete: { filter: {} } }]N/A[{ _delete: { filter: { ... } } }]

Key differences:

  • Create context supports only _connect and _create. Update context supports all five operations.
  • To-one in create context is a singular object. All update context relations use arrays.
  • Connect uses key (singular) for to-one, keys (plural array) for to-many.
  • Disconnect takes an empty object {} for to-one (there is only one link), a filter for to-many.
  • Create takes a single data object for to-one, an array for to-many.

Atomicity

All relational operations within a single request execute atomically within a single data source. If any operation fails, the entire request rolls back — no partial writes are persisted.

Atomicity is guaranteed only within a single data source. When a request crosses data source boundaries (e.g., writing to collections backed by different databases), there are no transactional guarantees across those boundaries. A dedicated page on transactional guarantees is planned for the future.

See Also

  • Field Selection — wildcards, nested fields, and expanded relation syntax
  • Filtering — filter syntax used in _disconnect, _update, and _delete
  • Writing Data — basic create, update, and delete operations
  • Type System — input types for create and update payloads
Copyright © 2026