title: Queries description: Local API, REST, and GraphQL query patterns
// Equals
{ color: { equals: 'blue' } }
// Not equals
{ status: { not_equals: 'draft' } }
// Greater/less than
{ price: { greater_than: 100 } }
{ age: { less_than_equal: 65 } }
// Contains (case-insensitive)
{ title: { contains: 'payload' } }
// Like (all words present)
{ description: { like: 'cms headless' } }
// In/not in
{ category: { in: ['tech', 'news'] } }
// Exists
{ image: { exists: true } }
// Near (point fields)
{ location: { near: [10, 20, 5000] } } // [lng, lat, maxDistance]
{
or: [
{ color: { equals: 'mint' } },
{
and: [
{ color: { equals: 'white' } },
{ featured: { equals: false } },
],
},
],
}
{
'author.role': { equals: 'editor' },
'meta.featured': { exists: true },
}
// Find documents
const posts = await payload.find({
collection: 'posts',
where: {
status: { equals: 'published' },
'author.name': { contains: 'john' },
},
depth: 2, // Populate relationships
limit: 10,
page: 1,
sort: '-createdAt',
locale: 'en',
select: {
title: true,
author: true,
},
})
// Find by ID
const post = await payload.findByID({
collection: 'posts',
id: '123',
depth: 2,
})
// Create
const post = await payload.create({
collection: 'posts',
data: {
title: 'New Post',
status: 'draft',
},
})
// Update
await payload.update({
collection: 'posts',
id: '123',
data: {
status: 'published',
},
})
// Delete
await payload.delete({
collection: 'posts',
id: '123',
})
// Count
const count = await payload.count({
collection: 'posts',
where: {
status: { equals: 'published' },
},
})
CRITICAL: Local API bypasses access control by default (overrideAccess: true).
// ❌ WRONG: User is passed but access control is bypassed
const posts = await payload.find({
collection: 'posts',
user: currentUser,
// Result: Operation runs with ADMIN privileges
})
// ✅ CORRECT: Respects user's access control permissions
const posts = await payload.find({
collection: 'posts',
user: currentUser,
overrideAccess: false, // Required to enforce access control
})
// Administrative operation (intentionally bypass access control)
const allPosts = await payload.find({
collection: 'posts',
// No user parameter, overrideAccess defaults to true
})
When to use overrideAccess: false:
import { stringify } from 'qs-esm'
const query = {
status: { equals: 'published' },
}
const queryString = stringify(
{
where: query,
depth: 2,
limit: 10,
},
{ addQueryPrefix: true },
)
const response = await fetch(`https://api.example.com/api/posts${queryString}`)
const data = await response.json()
GET /api/{collection} - Find documents
GET /api/{collection}/{id} - Find by ID
POST /api/{collection} - Create
PATCH /api/{collection}/{id} - Update
DELETE /api/{collection}/{id} - Delete
GET /api/{collection}/count - Count documents
GET /api/globals/{slug} - Get global
POST /api/globals/{slug} - Update global
query {
Posts(where: { status: { equals: published } }, limit: 10, sort: "-createdAt") {
docs {
id
title
author {
name
}
}
totalDocs
hasNextPage
}
}
mutation {
createPost(data: { title: "New Post", status: draft }) {
id
title
}
}
maxDepth on relationships to prevent over-fetchingselect to limit returned fieldsvirtual fields for computed datacontext