Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/alineacms/alinea/llms.txt

Use this file to discover all available pages before exploring further.

The cms object — created by createCMS and exported from your cms.ts file — is the primary interface for reading content. Under the hood it is backed by an in-memory SQLite database that is bundled with your Next.js build, so every call runs with zero network overhead and returns fully-typed results. There are three core query methods:
MethodReturns
cms.find(query)Promise<Array<Result>> — all matching entries
cms.get(query)Promise<Result> — single entry, throws if not found
cms.count(query)Promise<number> — count of matching entries
A fourth method, cms.first(query), works like cms.get() but returns null instead of throwing when no entry is found.

Finding multiple entries

Pass a type to constrain results to one content type and a select object to project exactly the fields you need.
app/blog/page.tsx
import {cms} from '@/cms'
import {BlogPost} from '@/cms'
import {Query} from 'alinea'

const posts = await cms.find({
  type: BlogPost,
  select: {
    _id: Query.id,
    title: BlogPost.title,
    publishDate: BlogPost.publishDate,
    slug: BlogPost.slug,
    excerpt: BlogPost.excerpt
  }
})
// posts is Array<{ _id: string; title: string; publishDate: string; slug: string; excerpt: string }>
Always use select to project only the fields your component needs. This avoids deserialising large rich-text or block fields that are unused.

Fetching a single entry

Use cms.get() when you expect exactly one result. The query throws an error if no matching entry is found, making it safe to use in Next.js generateStaticParams without null-checks.
app/blog/[slug]/page.tsx
// Fetch by a custom field value
const post = await cms.get({
  type: BlogPost,
  filter: {slug: {is: params.slug}},
  select: {
    title: BlogPost.title,
    body: BlogPost.body,
    publishDate: BlogPost.publishDate
  }
})
app/blog/[id]/page.tsx
// Fetch by entry id
const post = await cms.get({
  id: params.id,
  type: BlogPost,
  select: {
    title: BlogPost.title,
    body: BlogPost.body
  }
})
Use cms.first() when the entry may or may not exist:
app/blog/[slug]/page.tsx
const post = await cms.first({
  type: BlogPost,
  filter: {slug: {is: params.slug}}
})
if (!post) notFound()

Counting entries

cms.count() accepts the same query shape but returns an integer — useful for pagination metadata.
app/blog/page.tsx
const totalPosts = await cms.count({type: BlogPost})
const page = 1
const pageSize = 10

const posts = await cms.find({
  type: BlogPost,
  skip: (page - 1) * pageSize,
  take: pageSize
})

The GraphQuery shape

Every query method accepts a GraphQuery object. The complete set of top-level options is:
type
Type | Array<Type>
Constrain results to one or more content types.
select
SelectObject | Expr
Project specific fields or nested graph queries. When omitted, all EntryFields are returned.
include
SelectObject
Merge additional field projections on top of the default EntryFields result, without replacing the automatic type inference.
filter
Filter
Filter by entry fields or custom type fields. See Filtering & Ordering for the full filter API.
id
Condition<string>
Shorthand to filter by entry id. Accepts a plain string or a condition object.
parentId
Condition<string | null>
Filter entries by their direct parent id.
path
Condition<string>
Filter by the entry’s path segment.
url
Condition<string>
Filter by the full URL of the entry.
locale
string | null
Exact locale match. Use preferredLocale for a fallback strategy.
location
Root | Workspace | Page | Array<string>
Scope results to a workspace, root, or specific parent page.
orderBy
Order | Array<Order>
Sort results. Each Order object is {asc: Expr} or {desc: Expr}. See Filtering & Ordering.
take
number
Return at most N results.
skip
number
Skip the first N results.
Full-text search terms. Combine with Query.snippet() to highlight matches.
status
Status
Control which entry lifecycle statuses are included. Defaults to 'published'.

Status option

The status option controls which version of an entry is returned.
// Only published entries (default)
await cms.find({type: BlogPost, status: 'published'})

// Draft entries only
await cms.find({type: BlogPost, status: 'draft'})

// Archived entries only
await cms.find({type: BlogPost, status: 'archived'})

// Draft if available, otherwise published, otherwise archived
await cms.find({type: BlogPost, status: 'preferDraft'})

// Published if available, otherwise archived, otherwise draft
await cms.find({type: BlogPost, status: 'preferPublished'})

// All statuses in the database
await cms.find({type: BlogPost, status: 'all'})
'preferDraft' is useful in preview mode where you want editors to see unpublished changes. 'published' is the right default for public-facing pages.

Fully-typed results

Alinea infers the TypeScript return type directly from the query’s type and select parameters via Type.Infer<T>. No manual type annotations are needed.
cms.ts
import {Config, Field} from 'alinea'

export const BlogPost = Config.document('Blog post', {
  fields: {
    title: Field.text('Title'),
    slug: Field.path('Slug'),
    publishDate: Field.date('Publish date'),
    excerpt: Field.text('Excerpt'),
    body: Field.richText('Body')
  }
})
app/blog/page.tsx
import {cms, BlogPost} from '@/cms'

// TypeScript infers the full return type — no type assertions needed
const posts = await cms.find({
  type: BlogPost,
  select: {
    title: BlogPost.title,  // string
    slug: BlogPost.slug,    // string
    publishDate: BlogPost.publishDate  // string
  }
})

// posts: Array<{ title: string; slug: string; publishDate: string }>
The type parameter on cms.find<S, T, I> is resolved automatically from the query object literal, so TypeScript narrows the result array without any explicit generics.

Next steps

Filtering & Ordering

Apply filter, orderBy, take, and skip to your queries.

Graph Queries

Traverse children, parents, siblings, and translations inside a single query.

Editing API

Create, update, publish, and archive entries programmatically.

Configuration

Define content types, fields, workspaces, and roots.

Build docs developers (and LLMs) love