graft. docs

Getting started

Create a Graft project, compile content, and read it back typed.

This page gets you from an empty folder to a typed document. New to Graft? Start at What is Graft.

Prerequisites

  • Node.js 22.16 or newer. The static index's full-text search uses the node:sqlite build that ships from 22.16.0.
  • Nothing else. A content project needs no database and no object store.

Postgres is required only for operational data, typed functions, and copy-on-write branches. Add it later when you need one of those.

Quick start

static
  1. Scaffold a project

    pnpm dlx @usegraft/cli@beta init my-site
    cd my-site
    npx @usegraft/cli@beta init my-site
    cd my-site
    bunx @usegraft/cli@beta init my-site
    cd my-site

    Run it under the full package name. The bare name graft on npm belongs to an unrelated package.

    graft init writes graft.config.ts, content/pages/home.mdx, and the graft/ barrel for owned primitives. It scaffolds the static index by default.

  2. Compile and watch

    npx @usegraft/cli@beta compile   # validate content/ and write .graft/index.db
    npx @usegraft/cli@beta dev       # recompile when content or config changes

    Still the full package name, and still transient. graft init scaffolds graft.config.ts, content/, the graft/ barrel and llms.txt — it does not write a package.json or install anything, so there is no graft on your PATH yet. Add it to the project once you have a package.json and the short form works through your package manager:

    npm i -D @usegraft/cli@beta   # then: npx graft compile, or a "compile" script
  3. Read a document

    app/page.tsno database
    import { openStaticIndex } from "@usegraft/db";
    import { createClient } from "@usegraft/sdk-core";
    import { collections } from "../graft.config";
    
    const index = await openStaticIndex(".graft/index.db");
    const graft = createClient({ index, collections });
    
    const home = await graft.getDocument("pages", "home");
    //    ^? typed by your pages collection

.graft/index.db is derived from the files in git, so it is git-ignored. Rebuild it in your build command:

graft compile && next build

Move to Postgres

Postgres adds operational data, typed functions with access and approvals, and copy-on-write branches. Reach for one of those in static mode and Graft answers NEEDS_DATABASE, whose fix is these three steps.

Add your database URL to .env. Any parent directory works:

DATABASE_URL=postgres://…

Change one line in graft.config.ts:

export const index = "postgres";

Apply the schema that ships with @usegraft/db, then compile:

graft db migrate
graft compile

Reads move to a framework adapter, which takes the database instead of the artifact:

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

const graft = createGraft({ db, collections });
const home = await graft.getContent("pages", "home");

Author a document

Documents are MDX files. Frontmatter must satisfy the collection schema.

---
title: Hello, Graft
tagline: Content lives in git. Postgres is the index.
---

Body prose is real MDX. It is searchable and versioned with the repo.

Path shape: content/<collection>/<slug>.mdx. Slugs are kebab-case. A frontmatter slug: field overrides the filename.

Terms

TermMeaning
compileValidate MDX against the schema and write it to the index
indexThe queryable projection of your content. A SQLite artifact, or the content_index table on Postgres. Derived from git, so rebuild it with compile
projectYour Graft app directory (config + content/ + optional graft/)

Common failures

ErrorMeaningFix
CONFIG_NOT_FOUNDNo graft.config.ts above cwdRun graft init or cd into the project
ENV_VAR_MISSINGDATABASE_URL (or other required env) absentSet it in .env
NEEDS_DATABASEA Postgres-tier feature was used in static modeFollow Move to Postgres
INDEX_OWNERSHIPCompile would purge another project's collectionsUse a dedicated database (or branch) per project
CONTENT_DIR_NOT_FOUNDcontent/ missingCreate it or fix contentDir in config

Every Graft error includes a fix field. Do what it says, then retry.

Next steps

  • Schema — define collections and fields with defineCollection
  • Reading content — typed reads on six frameworks and in the browser
  • The agent surface — operate via MCP and the CLI
  • Deploy — self-host with a container or embed handlers