Live collections
Astro 6 introduced stable live content collections, which use a runtime
loader instead of static files. CaretCMS provides caretLoader to expose CMS
data through astro:content on Astro 6 and 7.
Use this guide after configuring server delivery and creating content in storage. A live collection does not create entries or Astro routes. It tells Astro how to read an existing CMS collection.
getLiveEntry('pages', 'home') then returns the latest CMS data on each request.
Prerequisites
Section titled “Prerequisites”- Astro 6.0+ stable
- Server delivery —
output: 'server'(live collections are dynamic by definition)
-
Create
src/live.config.tssrc/live.config.ts import { defineLiveCollection } from 'astro:content';import { caretLoader } from '@caretcms/core';const pages = defineLiveCollection({loader: caretLoader('pages'),});const site = defineLiveCollection({loader: caretLoader('site'),});const products = defineLiveCollection({loader: caretLoader('products'),});export const collections = { pages, site, products };One
defineLiveCollectioncall per CMS collection you want to query. -
Query in page frontmatter
src/pages/index.astro ---import { getLiveEntry, getLiveCollection } from 'astro:content';const { entry: home, error: homeError } = await getLiveEntry('pages', 'home');if (homeError) throw homeError;const { entries: allProducts, error: productsError } = await getLiveCollection('products');if (productsError) throw productsError;---<h1>{home?.data.headline ?? 'Default headline'}</h1><ul>{allProducts.map((p) => (<li>{p.data.name} — ${p.data.price}</li>))}</ul>getLiveEntryandgetLiveCollectioncome fromastro:content— they’re not CaretCMS APIs. Astro routes them to the registered loader behind the scenes. -
Pair with inline editing (optional)
---import { getLiveEntry } from 'astro:content';const { entry: home, error: homeError } = await getLiveEntry('pages', 'home');if (homeError) throw homeError;---<main data-caret-scope="pages::home"><h1 data-caret="headline">{home?.data.headline ?? 'Default headline'}</h1><p data-caret="intro">{home?.data.intro ?? 'Default intro'}</p></main>The page reads content during the server request, and the explicit bindings connect the displayed fields to the editor. Both use the same storage.
Values used in HTML attributes
Section titled “Values used in HTML attributes”For authenticated editors, the loader hides binding metadata inside string
values. Text rendered in the page body uses that metadata for automatic
click-to-edit. Before using a live string in a non-editable HTML attribute,
remove the metadata with stegaClean:
---import { stegaClean } from '@caretcms/core';import { getLiveEntry } from 'astro:content';const { entry: home, error } = await getLiveEntry('pages', 'home');if (error) throw error;const href = stegaClean(home?.data.ctaHref ?? '/');const description = stegaClean(home?.data.description ?? '');---
<meta name="description" content={description} /><a href={href}>{home?.data.ctaLabel}</a>This applies to values used in href, src, alt, <title>, metadata, and
other attributes. Keep visible text encoded so the editor can discover its
binding.
Filtering and querying
Section titled “Filtering and querying”Caret’s loader loads the collection; it does not implement query filters. Filter the returned array in your page:
---import { getLiveCollection } from 'astro:content';const { entries, error } = await getLiveCollection('products');if (error) throw error;const inStock = entries.filter((entry) => entry.data.in_stock === true);---This loads all entries into memory. For large collections, use getLiveEntry
for known IDs or implement a dedicated query layer.
Errors and missing data
Section titled “Errors and missing data”Check the returned error before using entry or entries:
---import { getLiveEntry } from 'astro:content';const { entry: home, error } = await getLiveEntry('pages', 'home');if (error) throw error;const headline = home?.data.headline ?? 'Welcome';---The loader returns a CaretLoaderError for storage failures and invalid single
entries. Collection reads skip invalid entries and log validation details while
returning valid entries. A missing or unpublished entry is unavailable to a
public read; handle that case with a fallback or your own 404 response.
The config filename and result shape follow Astro’s live content loader API.
Caching
Section titled “Caching”On Astro 7, published results include cache tags caret:<collection> and
caret:<collection>::<id>. Editor and private-preview results omit these hints.
Tags are metadata for a compatible cache; they do not install a CDN or configure
its invalidation for you. Astro 6 does not use the Astro 7 tags.
The loader reads storage on every render. If you add page, adapter, or CDN caching, keep authenticated and draft responses private and uncached, and invalidate public responses after publication. Missing cache hints alone do not prevent an independently configured proxy from caching a page.
Type safety
Section titled “Type safety”Add a schema to the Astro live collection to type and validate its returned
data. This is separate from registering a schema with CaretCMS for Studio:
import { defineLiveCollection } from 'astro:content';import { caretLoader } from '@caretcms/core';import { z } from 'zod';
const PageSchema = z.object({ headline: z.string(), intro: z.string(),});
const pages = defineLiveCollection({ loader: caretLoader('pages'), schema: PageSchema,});
export const collections = { pages };getLiveEntry('pages', 'home') then returns typed data.