Skip to content
Docs
    Menu

    Site code reference

    Reading CMS content in code

    How a page reads CMS collections with getLiveCollection and getLiveEntry, what it must declare, and how to handle missing items and fields.

    CMS collections aren't files. A page reads them with Astro's live-collection functions, imported from astro:content. Every collection is declared for you; you never write src/live.config.ts.

    A listing page

    ---
    // src/pages/blog.astro
    export const prerender = false
    import Base from '../layouts/Base.astro'
    import { getLiveCollection } from 'astro:content'
    
    const { entries: posts = [] } = await getLiveCollection('blogPost', {
      sort: 'publishedAt',
      order: 'desc',
      limit: 10,
    })
    ---
    
    <Base>
      <ul class="mx-auto flex max-w-3xl flex-col gap-6 px-6 py-16">
        {posts.map((post) => (
          <li>
            <a href={`/blog/${post.data.slug}`} class="font-display text-2xl text-ink-900 hover:text-accent-600">
              {post.data.title ?? 'Untitled'}
            </a>
          </li>
        ))}
      </ul>
    </Base>

    Each entry is { id, data }; data holds the item's fields.

    An item page

    Item pages have no getStaticPaths():

    ---
    // src/pages/blog/[slug].astro
    export const prerender = false
    import Base from '../../layouts/Base.astro'
    import { getLiveEntry } from 'astro:content'
    import Markdown from '@starjay/design-system/components/cms/Markdown.astro'
    
    const { entry } = await getLiveEntry('blogPost', { slug: Astro.params.slug })
    if (!entry) return new Response(null, { status: 404 })
    const post = entry.data
    ---
    
    <Base>
      <article class="mx-auto max-w-2xl px-6 py-16">
        <h1 class="font-display text-4xl text-ink-900">{post.title}</h1>
        {post.body && <Markdown value={post.body} class="mt-8 text-lg text-ink-700" />}
      </article>
    </Base>

    Look an item up by { slug } when its collection has a slug field. Otherwise look it up by id: getLiveEntry('blogPost', Astro.params.id).

    Query options

    All options are optional.

    Option What it does
    where Field → value, or an operator object: $eq, $ne, $gt, $gte, $lt, $lte, $in, $contains, $all, $exists
    search Text search
    sort A field to sort by
    order 'asc' or 'desc'
    limit, offset Paging
    expand Reference fields to replace with the item they point to
    const { entries: featured = [] } = await getLiveCollection('product', {
      where: { category: 'chairs', price: { $lte: 500 } },
      expand: ['designer'],
    })

    Which fields can be queried

    where, search and sort work only on short top-level fields: text, slugs, numbers, dates, true/false, choices, links, images, references, and plain lists of those. Long text, Markdown and grouped fields (objects, mixed lists) can't be queried. Read the items, then use those fields in the page.

    Why every field may be missing

    A draft item may be incomplete. A published item doesn't have a field that was added, or made required, after it was published. Guard every field: {post.data.subtitle && <p>{post.data.subtitle}</p>}.

    How these pages behave

    Pages that read collections render on request. The live site caches them until the content changes. A page that must differ for each visitor (because it reads cookies or request headers) calls Astro.cache.set(false).

    A collection needs at least one item before its item page has anything to show. Listings show only published items on the live site; see CMS pages on the live site.

    Related