Ordering And Cursors Use explicit ordering, distinct, offset, custom order lists, and cursor pagination. core reference core/ordering-cursors core/ordering-cursors.md

Ordering And Cursors

Use explicit ordering, distinct, offset, custom order lists, and cursor pagination.

Explicit ordering

GraphQL
query {
  products(order_by: { price: desc, id: asc }, limit: 5) {
    id
    price
  }
}

Always specify order_by when the order matters. SQL databases do not guarantee result ordering without it.

Ordering can target multiple columns, nested related tables, custom value lists, and null placement:

GraphQL
query Products($ids: [Int!]) {
  products(
    order_by: {
      id: [$ids, "asc"]
      price: { dir: desc, nulls: last }
    }
    where: { id: { in: $ids } }
    limit: 5
  ) {
    id
    price
  }
}
Verified by Example_queryWithOrderByList tests/query_test.go:306

Distinct and offset

GraphQL
query {
  products(
    limit: 5
    offset: 10
    distinct: [price]
    order_by: { price: desc }
  ) {
    id
    price
  }
}
Verified by Example_queryWithLimitOffsetOrderByDistinctAndWhere tests/query_test.go:338
GraphQL
query {
  products(order_by: { users: { email: desc }, id: desc }, limit: 5) {
    id
    price
  }
}
Verified by Example_queryWithNestedOrderBy tests/query_test.go:279

Named cursors

Cursor fields let clients page through stable result sets. Request the cursor at the root level and pass it back through variables.

GraphQL
query ProductsPage($products_cursor: Cursor) {
  products(
    first: 10
    after: $products_cursor
    order_by: { id: asc }
  ) {
    id
    name
  }

  products_cursor
}
JSON
{ "products_cursor": null }

On the next page, set products_cursor to the returned value. Cursors are opaque; do not construct or parse them.

Verified by Example_queryWithNamedCursorPagination tests/query_test.go:2086
Verified by Example_queryWithNestedIndependentCursors tests/query_test.go:2296

Cursor rules

RuleReason
Use after: $products_cursor or before: $products_cursor.Cursors must be variables, not string literals embedded in the query.
Request products_cursor at the query root.Cursor fields describe the page, not each row.
Keep variable names cursor-shaped, such as products_cursor or cursor.MCP cursor expansion only touches cursor variables.
Treat returned values as opaque.GraphJin uses encrypted cursor payloads and a dynamic security prefix.
Do not hardcode gj- or __gj-enc:.gj-...: is generated from the active security context, and __gj-enc: is an MCP cache transport detail.

Verified by TestExpandCursorIDs_AlreadyEncrypted serv/mcp_cursor_test.go:161
Verified by Example_queryWithNamedCursorInvalidVariable tests/query_test.go:2152

Backward pagination

GraphQL
query PreviousProducts($products_cursor: Cursor) {
  products(
    last: 10
    before: $products_cursor
    order_by: { id: asc }
  ) {
    id
    name
  }

  products_cursor
}

Backward and forward pagination use the same root-level cursor field. Keep the ordering stable in both directions.

Verified by Example_queryWithBackwardCompatibleCursor tests/query_test.go:2091
Docs