Skip to main content

Best Practices

Commit Early, Commit Often

Graft commits are cheap. Each commit stores only the files that changed (via content-addressed deduplication). Commit whenever you reach a meaningful state:
# Before running migrations
graft commit -m "before schema migration"

# After seeding test data
graft commit -m "seeded with 50K customer records"

# Before destructive experiments
graft commit -m "baseline before refactor"

Branch Naming

Use descriptive branch names that reflect the purpose or experiment:
graft checkout payment-v2-migration
graft checkout before-pg-upgrade
graft checkout load-test-baseline

Use Bind Mount Mode

For daily use, always initialize with --bind:
graft init my-postgres --bind
Bind mount mode makes commits and checkouts faster by eliminating the Alpine runner bridge step.

Verify After Critical Operations

After commits on important branches (especially main), verify integrity:
graft commit -m "production-like data"
graft verify main

One Project Per Container

Each Graft project maps to one target container. If you have multiple database containers (e.g., Postgres + Redis), initialize Graft on each separately:
graft init my-postgres --bind
graft init my-redis --bind
Each gets its own directory under ~/.graft/.

Pair with Seedling

Graft pairs naturally with Seedling for reproducible test data:
# Seed deterministically
seedling generate --count 1000 --seed 42 --db "$DATABASE_URL"

# Capture as a save point
graft commit -m "deterministic seed (1000 rows, seed 42)"

# Restore to this exact state any time
graft checkout test-baseline

What Not to Do

  • Don’t modify branch directories manually while the container is running. The database engine may overwrite your changes.
  • Don’t delete graft.db manually — it contains the DAG that traces all commit history. Deleting it loses all integrity tracking.
  • Don’t run multiple Graft instances on the same project simultaneously. The SQLite database uses a single connection and concurrent access is untested.