Ordering

February 15, 2026 ยท View on GitHub

Client Controlled Ordering

To enable clients to control the ordering, use @orderBy on an argument of a field that is backed by a database query.

type Query {
  posts(orderBy: _ @orderBy(columns: ["posted_at", "title"])): [Post!]! @all
}

The type of the argument can be left blank as _ , as Lighthouse will automatically generate an input that takes enumerated column names, together with the SortOrder enum. Add that to your schema:

"Order by clause for Query.posts.orderBy."
input QueryPostsOrderByOrderByClause {
  "The column that is used for ordering."
  column: QueryPostsOrderByColumn!

  "The direction that is used for ordering."
  order: SortOrder!
}

"Allowed column names for Query.posts.orderBy"
enum QueryPostsOrderByColumn {
  POSTED_AT @enum(value: "posted_at")
  TITLE @enum(value: "title")
}

"Directions for ordering a list of records."
enum SortOrder {
  "Sort records in ascending order."
  ASC

  "Sort records in descending order."
  DESC
}

Querying a field that has an orderBy argument looks like this:

{
  posts(orderBy: [{ column: POSTED_AT, order: ASC }]) {
    title
  }
}

Secondary Ordering

You may pass more than one sorting option to add a secondary ordering.

{
  posts(
    orderBy: [{ column: POSTED_AT, order: ASC }, { column: TITLE, order: DESC }]
  ) {
    title
  }
}

Reuse Columns Enum

To re-use a list of allowed columns, define your own enumeration type and use the columnsEnum argument instead of columns:

type Query {
  allPosts(orderBy: _ @orderBy(columnsEnum: "PostColumn")): [Post!]! @all
  paginatedPosts(orderBy: _ @orderBy(columnsEnum: "PostColumn")): [Post!]!
    @paginate
}

"A custom description for this custom enum."
enum PostColumn {
  # Another reason why you might want to have a custom enum is to
  # correct typos or bad naming in column names.
  POSTED_AT @enum(value: "postd_timestamp")
  TITLE @enum(value: "title")
}

Lighthouse will still automatically generate the necessary input types and the SortOrder enum. Instead of generating enums for the allowed columns, it will simply use the existing PostColumn enum.

Ordering By Relations

You can allow clients to order a list of models by an aggregated value of their relations. You must specify which relations and which of their columns are allowed.

type Query {
  users(
    orderBy: _
      @orderBy(relations: [{ relation: "tasks", columns: ["difficulty"] }])
  ): [User!]! @all
}

Lighthouse will automatically generate the appropriate input types and enum values.

{
  users(
    orderBy: [
      { tasks: { aggregate: COUNT }, order: ASC }
      { tasks: { aggregate: MAX, column: DIFFICULTY }, order: DESC }
    ]
  ) {
    id
  }
}

Predefined Ordering

To predefine a default order for your field, use @orderBy on a field:

type Query {
  latestUsers: [User!]! @all @orderBy(column: "created_at", direction: DESC)
}

Clients won't have to pass any arguments to the field and still receive ordered results by default.