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:sqlitebuild 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
staticScaffold a project
pnpm dlx @usegraft/cli@beta init my-site cd my-sitenpx @usegraft/cli@beta init my-site cd my-sitebunx @usegraft/cli@beta init my-site cd my-siteRun it under the full package name. The bare name
grafton npm belongs to an unrelated package.graft initwritesgraft.config.ts,content/pages/home.mdx, and thegraft/barrel for owned primitives. It scaffolds the static index by default.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 changesStill the full package name, and still transient.
graft initscaffoldsgraft.config.ts,content/, thegraft/barrel andllms.txt— it does not write apackage.jsonor install anything, so there is nografton your PATH yet. Add it to the project once you have apackage.jsonand the short form works through your package manager:npm i -D @usegraft/cli@beta # then: npx graft compile, or a "compile" scriptRead 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
| Term | Meaning |
|---|---|
| compile | Validate MDX against the schema and write it to the index |
| index | The queryable projection of your content. A SQLite artifact, or the content_index table on Postgres. Derived from git, so rebuild it with compile |
| project | Your Graft app directory (config + content/ + optional graft/) |
Common failures
| Error | Meaning | Fix |
|---|---|---|
CONFIG_NOT_FOUND | No graft.config.ts above cwd | Run graft init or cd into the project |
ENV_VAR_MISSING | DATABASE_URL (or other required env) absent | Set it in .env |
NEEDS_DATABASE | A Postgres-tier feature was used in static mode | Follow Move to Postgres |
INDEX_OWNERSHIP | Compile would purge another project's collections | Use a dedicated database (or branch) per project |
CONTENT_DIR_NOT_FOUND | content/ missing | Create 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