§01|Preview branches

seed every supabase preview branch.


Supabase preview branches ship with an empty database. Run satus once after the branch is created and every PR review gets a fully seeded environment. The 10,000-row safety guard is harmless here: preview branches start at zero.

# pull the postgres url from the supabase CLI
$ export DATABASE_URL=$(supabase --experimental branches get $BRANCH --output json | jq -r .POSTGRES_URL)
$ export OPENAI_API_KEY=$OPENAI_API_KEY
# seed it. one transaction. all-or-nothing.
$ satus generate --profile e-commerce --seed 42
✓ 4,812 rows · $0.07 · 11.4s
note

Pin --seed so a re-run on the same branch produces identical data. Reviewers can deep-link to a specific row by ID and trust it stays put.

§02|GitHub Actions

one job. one step. one secret per env.


The most common shape. Plan in PR jobs (no writes, free), generate on merge to main or against ephemeral DBs.

# .github/workflows/seed.yml
$ name: seed
$ on: { pull_request: {}, push: { branches: [main] } }
$ jobs:
$ seed:
$ runs-on: ubuntu-latest
$ steps:
$ - uses: actions/checkout@v4
$ - uses: actions/setup-node@v4
$ with: { node-version: 20 }
$ - run: npm i -g @passkeybridge/satus
$ - run: satus plan --profile saas-subscriptions --json
$ if: github.event_name == 'pull_request'
$ - run: satus generate --profile saas-subscriptions
$ if: github.ref == 'refs/heads/main'
$ env:
$ DATABASE_URL: ${{ secrets.DATABASE_URL }}
$ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
note

satus plan --json is read-only and needs no DB credentials when given --schema ./schema.sql. Use it as a PR check to catch schema-breaking changes before merge.

§03|E2E reset

fresh data between every test suite.


Cypress, Playwright, and Vitest E2E suites need a known-good database state. The pattern: truncate user tables, then satus generate --seed with a fixed seed. The fixed seed gives every test the same starting rows.

# scripts/reset-test-db.sh
$ #!/usr/bin/env bash
$ set -euo pipefail
# 1 · truncate everything user-owned in a single tx
$ psql "$DATABASE_URL" -c "TRUNCATE \
$ orders, order_items, products, customers \
$ RESTART IDENTITY CASCADE;"
# 2 · re-seed with a fixed seed for deterministic IDs
$ satus generate --profile e-commerce --seed 1 --force
note

--force is required here because the truncate may leave residual rows in tables satus doesn't own. Wire this into Cypress's before(...) hook or Playwright's globalSetup.

§04|Neon branching

seed a fresh neon branch in one shell.


Neon's copy-on-write branches make per-developer or per-PR databases cheap. Combine that with satus and every engineer gets their own seeded database for the cost of the branch metadata.

# create a branch and capture its connection string
$ BRANCH=$(neon branches create --name pr-$PR --project-id $NEON_PROJECT_ID --output json)
$ export DATABASE_URL=$(echo "$BRANCH" | jq -r .connection_uris[0].connection_uri)
# seed
$ satus generate --profile saas-subscriptions
note

Tear the branch down on PR close. Neon charges per active branch—a stale fleet of seeded branches will surprise the bill.

Have a recipe you want documented? Email support@satus.sh. We add the most-requested integrations first.