← Files InsForgeARCHIVED FILE
skills/insforge-cli/references/branch/overview.md
8.33 KB · Oct 5, 2026 · 18:29 UTC
# Backend Branches — `npx @insforge/cli branch` A branch is a full child of the parent project: own EC2, own PostgreSQL, own storage namespace. It shares the parent's `JWT_SECRET` (same users authenticate) but gets fresh `API_KEY` / `ANON_KEY`. Use it to test schema, RLS, auth, or function changes in isolation before merging back to parent. Branching is **not free** — each branch consumes an EC2 instance. Use it when isolation pays off. ## When to use a branch **Strong signals — branch first:** - Destructive DDL on existing tables (`DROP TABLE`, `DROP COLUMN`, `ALTER COLUMN TYPE`). `git revert` doesn't restore lost data. - New or modified RLS policies on user-data tables. RLS bugs are silent — prod users lock out or get unintended access. - Auth provider config changes (OAuth providers, redirect URIs, SMTP). Bricks prod login if wrong. - Multi-step refactors touching >3 tables or >1 schema. **Moderate signals — branch if convenient:** - Adding a new table or column (additive). - Email templates, AI gateway config, cron schedule changes. **Skip the branch:** - Row-data-only changes (insert/update). Branching is about schema, not data. - Client-side fixes that don't touch the backend. - Edge-function logic-only changes covered by unit tests. - Anything `git revert` handles faster. ## Mode selection | Mode | When | | ---------------- | -------------------------------------------------------------------------------------------------------------------- | | `full` (default) | Need realistic data — RLS testing with real rows, query plan tuning, large-table migrations. | | `schema-only` | Synthetic seed rows are enough. Faster to create. User-data tables (`auth.users`, `storage.objects`, …) start empty. | Mode is **fixed at create time** — `branch reset` uses the original dump. Need a different mode → delete + recreate. ## Lifecycle commands ### `branch create <name> [--mode full|schema-only] [--no-switch]` Creates a branch from the linked parent and auto-switches the directory's context to it (unless `--no-switch`). Provisioning takes 30–120 s for small DBs, longer for large. `<name>`: 1–64 chars, `[a-zA-Z0-9-]`, must start with letter/digit, unique per parent. After creation: 1. **Re-source your dev server's `.env`** — `INSFORGE_URL` / `INSFORGE_ANON_KEY` change with the switch. 2. **Deploy code that lives outside the database.** `pg_dump` copies `functions.definitions` rows but not the Deno Subhosting bundles, Vercel frontends, or Fly.io compute services — the branch's runtime starts empty. Run `functions deploy <slug>`, `deployments deploy`, and `compute deploy` for anything you need on the branch (`compute deploy`, not `compute update` — there's no service id to update yet). Symptom if you skip this: function invocations fail with `getaddrinfo ENOTFOUND deno` or `Deployment not found`. ### `branch list` Lists active branches of the parent (or, when on a branch, that branch's siblings). The leading column shows `*` for the branch the directory is currently switched onto. | State | Meaning | | ----------- | ---------------------------------------------------------------------------------------------------------------------- | | `creating` | Provisioning EC2 + restoring pg_dump (30–120 s). | | `ready` | Usable — can be switched, modified, merged, or reset. | | `merging` | Merge in progress (usually < 30 s). | | `merged` | Last merge succeeded. Dormant — `branch reset` rewinds to T0 and flips back to `ready` so the same slot can be reused. | | `resetting` | `branch reset` is restoring the T0 dump in place. | | `deleted` | Soft-delete tombstone (filtered from `list`). | ### `branch switch <name>` / `--parent` Repoints `.insforge/project.json` at the branch (or back at the original parent). Refuses if the target branch isn't `ready`. > **Critical:** the dev server's `.env` is **not** updated by `switch`. The SDK reads `INSFORGE_URL` / `INSFORGE_ANON_KEY` from `.env`, so without re-sourcing, the SDK silently keeps hitting the previous backend. This is the #1 source of "I switched but my changes aren't showing up." > **Also:** each backend has its own function / frontend / compute runtime. Switching points the SDK at a different EC2 whose Deno Subhosting, Vercel, and Fly.io state are independent. If you've never deployed your code on the target (e.g. first switch to a freshly-created branch), deploy it with `functions deploy`, `deployments deploy`, and `compute deploy` — otherwise calls land on an empty runtime and fail with `getaddrinfo ENOTFOUND deno` / `Deployment not found`. The first hop off the parent backs up `.insforge/project.json` to `.insforge/project.parent.json`. Subsequent branch ↔ branch switches don't touch the backup — `--parent` always returns to the original. ### `branch delete <name> [-y]` Deletes a branch and reclaims its EC2. Auto-`switch --parent` if the directory is currently on the deleted branch. **Irreversible** — branch data is lost. Already-merged branches: deletion still works (the merge has already landed on parent). ## Reset vs. delete + recreate | Want to… | Reach for | | ----------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | Rerun the experiment from a clean T0, keep the same `API_KEY` / URL so dev-server config is unchanged | `branch reset` | | A different `--mode` (mode is fixed at create time) | delete + create | | A fresh `appkey` / API key so callers can't talk to the old branch | delete + create | | Re-merge a branch already in `merged` with new changes layered on T0 | `branch reset` (re-opens the slot), make new changes, `branch merge` again | See [branch reset](reset.md) for what reset does and does not touch. ## Failure modes | Error | Meaning | Fix | | ------------------------------ | -------------------------------------------------------------- | --------------------------- | | `branch.quota_exceeded` | Per-org cap (3 parents) or per-parent cap (2 branches) reached | Delete an old branch first | | `branch.parent_not_branchable` | Parent is itself a branch / not active / pre-2.x | Use a top-level 2.x project | | `branch.name_conflict` | Branch name already exists on this parent | Pick a different name | | `branch.not_found` | No branch with that name on the parent | Check `branch list` | | `branch.busy` | Branch is `creating` / `merging` / `resetting` | Wait for the in-flight op | | `branch.not_ready` | Branch isn't in `ready` state for this op | Wait or check state | ## Limits - Per-org: max 3 parent projects with active branches (configurable). - Per-parent: max 2 active branches (configurable). - Branches do not nest (no branch-of-a-branch). - Branches do not auto-resume when the parent resumes — resume manually. - Branches are deleted (cascade) when the parent project is deleted. ## See also - [branch merge](merge.md) — merging a branch back to parent (dry-run, conflict resolution, what gets applied) - [branch reset](reset.md) — rewinding a branch to T0 (recovery / re-merge)
SHA-256: d45101b23208e3d0745c3cb4cacefc6cd4723ddd63fa1a936905d1e077acc5f3