Skip to content
Docs

Queries

Every table query in BifrostQL returns paged results. The table name is the query field, and results live inside a data array.

{
users(limit: 10, offset: 0) {
data {
userId
name
email
}
}
}

The limit and offset parameters control pagination. Without limit, the default page size from your configuration applies.

Filters use Directus-style syntax. Pass a filter argument with column names and operators:

{
orders(filter: { status: { _eq: "shipped" }, total: { _gt: 100 } }) {
data {
orderId
total
status
}
}
}
OperatorDescriptionExample
_eqEqual{ status: { _eq: "active" } }
_neqNot equal{ status: { _neq: "deleted" } }
_gtGreater than{ price: { _gt: 50 } }
_gteGreater than or equal{ price: { _gte: 50 } }
_ltLess than{ price: { _lt: 100 } }
_lteLess than or equal{ price: { _lte: 100 } }
_inIn list{ status: { _in: ["active", "pending"] } }
_ninNot in list{ status: { _nin: ["deleted"] } }
_containsContains substring{ name: { _contains: "smith" } }
_ncontainsDoes not contain{ name: { _ncontains: "test" } }
_starts_withStarts with{ name: { _starts_with: "A" } }
_ends_withEnds with{ email: { _ends_with: ".com" } }
_nullIs null{ deletedAt: { _null: true } }
_nnullIs not null{ email: { _nnull: true } }
_betweenBetween two values{ price: { _between: [10, 50] } }

Multiple fields at the same level are combined with AND:

{
products(filter: { price: { _gt: 10 }, category: { _eq: "electronics" } }) {
data { productId name price }
}
}

Use _and and _or for explicit boolean logic:

{
products(filter: {
_or: [
{ price: { _lt: 10 } },
{ category: { _eq: "sale" } }
]
}) {
data { productId name price category }
}
}

Sort uses an enum list. Each column has _asc and _desc variants:

{
products(sort: [price_asc, name_desc]) {
data {
productId
name
price
}
}
}

Sort fields are applied in order. The first field is the primary sort, subsequent fields break ties.

Combine limit and offset for pagination:

# Page 1
{ users(limit: 20, offset: 0) { data { userId name } } }
# Page 2
{ users(limit: 20, offset: 20) { data { userId name } } }

The total field on the page type returns the count of all matching rows (before pagination):

{
users(limit: 20, offset: 0) {
total
data {
userId
name
}
}
}

Request only the fields you need. BifrostQL generates SQL that selects only the requested columns, so narrower queries are genuinely faster at the database level.

{
users {
data {
userId
email
}
}
}

This produces SELECT [userId], [email] FROM [users] — not SELECT *.