Reading content

Get a document, list a collection, or search it. The same three calls work in every framework.

Content3 min read

Once your content is compiled, your app reads it through a Graft client. This page covers the three reads you will use everywhere, the options they take, and how to read from a branch or from another server.

Your framework guide shows where to create the client. Every example below assumes one called graft.

Read one document

getContent takes a collection and a slug, and returns the document or null if it does not exist:

const home = await graft.getContent("pages", "home");

if (home) {
  home.data.title; // string, typed from your schema
  home.body;       // the Markdown or MDX body, as written
}

List a collection

listContent returns every document in a collection. Pass limit and offset to page through a long one:

const posts = await graft.listContent("posts", { limit: 20, offset: 0 });

Search a collection

searchContent runs a full-text search and returns the best matches first, each with a highlighted snippet of the matching text:

const hits = await graft.searchContent("docs", "preview branch");

Search explains the query syntax and how results are ranked.

Every read checks each document against your schema on the way out. Deleted documents are skipped. A document that fails the check is not: the read throws SCHEMA_VALIDATION_FAILED, naming the document and the field, and a list or search that includes it fails as a whole. You never receive a document whose fields do not match its type. graft compile runs the same check, so this only happens when the index was built from files that no longer match the schema.

Why the names differ outside a framework

The framework packages call these reads getContent, listContent, and searchContent. Underneath, they all use @usegraft/sdk-core, whose methods are named getDocument, listDocuments, and searchDocuments. They take the same arguments and return the same types. Use the sdk-core names only when you call it directly, in a script or a tool with no framework.

Read from a preview branch

Pass branch to any read to get content from a preview branch instead of main:

const page = await graft.getContent("pages", "pricing", { branch: "preview-pricing" });

Branches need the Postgres engine. On the static engine the option is accepted and ignored, because each Git checkout compiles its own index.

Read from another server

Sometimes the app that renders pages cannot open the index itself, for example when it runs on a different host from your content. In that case, point the client at a Content API served by graft serve. Your reads stay exactly the same:

import { createContentApiReader } from "@usegraft/content-api";
import { createGraft } from "@usegraft/sdk-astro";
import { collections } from "../../graft.config";

export const graft = createGraft({
  index: createContentApiReader({
    endpoint: "https://cms.example.com/api/content/v1",
    headers: { authorization: `Bearer ${process.env.GRAFT_CONTENT_TOKEN}` },
  }),
  collections,
});

Each Content API endpoint serves one branch, so a production app cannot be switched onto preview content by a request parameter.

Your framework