Skip to content
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
1baf8ea
feat(cli): bundle pg-delta next engine
avallete Aug 6, 2026
8078b53
chore: merge develop into pg-delta next
avallete Aug 6, 2026
4b697a2
fix(cli): allow pg-topo parser build script
avallete Aug 6, 2026
c52cf53
fix(cli): embed libpg-query wasm in compiled binary
avallete Aug 6, 2026
1f82bf9
feat(cli): isolate pg-delta next shadow databases
avallete Aug 7, 2026
5bffecb
fix(cli): correct diff and migration execution contracts
avallete Aug 7, 2026
f12b1b9
chore: merge develop into pg-delta next
avallete Aug 7, 2026
958d36c
test(cli): update transactional Go mocks
avallete Aug 7, 2026
d486195
chore(cli): remove unused diff helper
avallete Aug 7, 2026
394ecf8
fix(cli): isolate pg-delta-next baseline behavior
avallete Aug 8, 2026
9f66d41
chore: merge develop into pg-delta next
avallete Aug 8, 2026
438a9ac
fix(cli): warn about manifestless declarative removals
avallete Aug 8, 2026
0ebe58c
fix(cli): warn on pg-delta coverage gaps
avallete Aug 8, 2026
dcdf7e0
fix(cli): format pg-delta SQL by default
avallete Aug 8, 2026
16028da
fix(cli): clarify declarative diff baselines
avallete Aug 8, 2026
b7ad988
test(cli): use malformed branch response type
avallete Aug 8, 2026
7f6fb32
chore(cli): update pg-delta next preview
avallete Aug 8, 2026
f9bd289
feat(cli): improve declarative schema upgrade flow
avallete Aug 8, 2026
46a1614
fix(cli): address pg-delta next review findings
avallete Aug 8, 2026
ca55d8a
chore(cli): use published pg-delta alpha
avallete Aug 9, 2026
f92a8b7
Merge remote-tracking branch 'origin/develop' into feat/upgrade-pg-de…
avallete Aug 10, 2026
9f264e9
fix(cli): address pg-delta next rollout blockers
avallete Aug 11, 2026
0879ced
fix(cli): add pg-net webhook remediation
avallete Aug 11, 2026
3f0428f
fix(cli): scope pg-delta next schema filters
avallete Aug 11, 2026
1bc9e6b
fix(cli): diff pg-delta next against live local database
avallete Aug 11, 2026
be38f7b
fix(cli): preserve migration transaction metadata
avallete Aug 11, 2026
0139811
fix(cli): converge database webhooks configuration
avallete Aug 11, 2026
ab8423b
fix(cli): harden pg-delta schema workflows
avallete Aug 12, 2026
f00da06
Merge remote-tracking branch 'origin/develop' into feat/upgrade-pg-de…
avallete Aug 12, 2026
db04525
Merge branch 'develop' into feat/upgrade-pg-delta-next
avallete Aug 13, 2026
f27874c
chore(cli): trim pg-delta PR scope
avallete Aug 13, 2026
3b2bb55
Merge remote-tracking branch 'origin/develop' into feat/upgrade-pg-de…
avallete Aug 14, 2026
cea474d
Merge remote-tracking branch 'origin/develop' into feat/upgrade-pg-de…
avallete Aug 14, 2026
23814e7
feat(cli): upgrade pg-delta next to alpha.40
avallete Aug 14, 2026
a621690
fix(cli): address pg-delta engine review findings
avallete Aug 14, 2026
c3c4643
fix(cli): recover legacy declarative extension gaps
avallete Aug 14, 2026
b2b7cb9
refactor(cli): trim pg-delta next change set
avallete Aug 14, 2026
3b5d564
Merge remote-tracking branch 'origin/develop' into feat/upgrade-pg-de…
avallete Aug 14, 2026
c360231
fix(cli): preserve declarative sync context
avallete Aug 14, 2026
2cc84ab
fix(cli): preserve migration-owned pg-net
avallete Aug 14, 2026
d742d4a
fix(cli): keep staged declarative exports outside the active tree
avallete Aug 15, 2026
27a56e6
fix(cli): replace staged-dir trim regex with a linear scan
avallete Aug 15, 2026
f7e27f1
fix(cli): unify declarative compat-gate recovery guidance
avallete Aug 15, 2026
3223646
docs(cli): add shadow-db startup performance plan (readiness gate + w…
avallete Aug 13, 2026
9d999d2
fix(cli): gate shadow readiness on a direct connect probe (~6.5s/prov…
avallete Aug 13, 2026
3c2d4e4
fix(cli): exec the postgres entrypoint so containers stop in ~1s
avallete Aug 13, 2026
008256e
feat(cli): cache the shadow baseline as a PGDATA snapshot (default on)
avallete Aug 13, 2026
9328775
refactor(cli): extract generic PGDATA snapshot primitives, trim cache…
avallete Aug 13, 2026
8c55123
docs(cli): note the frozen/online hot-save modes on the PGDATA export…
avallete Aug 13, 2026
8894334
fix(cli): harden the shadow baseline cache against review findings
avallete Aug 13, 2026
4520ac9
docs(cli): record deferred shadow-cache review follow-up (init SQL ke…
avallete Aug 13, 2026
cbace05
fix(cli): key shadow snapshots by registry-resolved job images, inter…
avallete Aug 13, 2026
9925338
fix(cli): fold the CLI-embedded baseline SQL into the shadow cache key
avallete Aug 13, 2026
02e7b36
fix(cli): resolve the shadow JWKS effect once per run
avallete Aug 13, 2026
b3bc652
fix(cli): honor the shadow cache opt-out from project dotenv, documen…
avallete Aug 13, 2026
7956603
fix(cli): make OrioleDB shadows cache-ineligible, collision-proof vau…
avallete Aug 13, 2026
7d033e4
docs(cli): narrow the snapshot tar's Files Written conditions to cold…
avallete Aug 13, 2026
45c3fb1
chore(cli): format SIDE_EFFECTS tables
avallete Aug 13, 2026
cda6d4f
fix(cli): make --no-cache bypass the shadow snapshot, hash only what …
avallete Aug 13, 2026
714a7bd
fix(cli): keep uncached shadow runs on one session, sweep abandoned p…
avallete Aug 13, 2026
d9f7467
fix(cli): hash the effective root key into the shadow cache key
avallete Aug 13, 2026
a256f4f
fix(cli): only discard the shadow snapshot when its contents are impl…
avallete Aug 13, 2026
bcdf030
fix(cli): fold the vault upsert SQL into the baseline digest
avallete Aug 13, 2026
1e1b7fa
docs(cli): record the warm-aware catalog-shadow follow-up from the CL…
avallete Aug 13, 2026
ebe339a
docs(cli): list the partial-snapshot sweep under Files Read
avallete Aug 13, 2026
607107b
fix(cli): exclusive-create the snapshot temp file so its mode can nev…
avallete Aug 13, 2026
26147ad
fix(cli): fail the run when the shadow cannot come back after the bas…
avallete Aug 13, 2026
0890779
fix(cli): make PG<=14 cache-ineligible, sweep partials on warm hits, …
avallete Aug 13, 2026
502aefc
fix(cli): attach the exec-format recovery hint to shadow readiness fa…
avallete Aug 14, 2026
29aa7e3
refactor(cli): drop PG<=14-only SQL from the shadow baseline digest
avallete Aug 14, 2026
0073867
fix(cli): pass shadow setup options on the cold migrate path
avallete Aug 15, 2026
0621666
fix(cli): store shadow baseline cache under SUPABASE_HOME
avallete Aug 15, 2026
4be4d0c
fix(cli): warm-cache pg-delta next shadows
avallete Aug 15, 2026
e342263
docs(cli): clarify explicit diff output contract
avallete Aug 15, 2026
7a8fa09
fix(cli): key shadow snapshots by the effective webhooks policy
avallete Aug 15, 2026
0854051
chore(cli): merge develop into pg-delta next
avallete Aug 15, 2026
788e918
chore(cli): merge pg-delta next into shadow database cache
avallete Aug 15, 2026
e912767
feat(cli): upgrade pg-delta next to alpha.41
avallete Aug 15, 2026
68d524e
Merge branch 'feat/upgrade-pg-delta-next' into avallete/shadow-db-per…
avallete Aug 15, 2026
09d8c6c
fix(cli): allow restored shadows to share database identity
avallete Aug 15, 2026
e3f59a6
Merge remote-tracking branch 'origin/develop' into avallete/supabase-…
avallete Aug 17, 2026
b82b010
test(cli): drop duplicated mock engine block from the develop merge
avallete Aug 17, 2026
e06434e
fix(cli): harden the shadow cache against review findings
avallete Aug 17, 2026
b057c0e
docs(cli): complete generate's shadow-cache checklist, log deferred r…
avallete Aug 17, 2026
0430203
docs(cli): log the Realtime seeded-host warm-restore follow-up
avallete Aug 17, 2026
40dfa48
fix(cli): key migra-path shadow snapshots by the migrate the mode wil…
avallete Aug 17, 2026
04dd100
test(cli): pin the LRU victim's mtime in the retention test
avallete Aug 17, 2026
9970ce4
test(cli): pin the handlers' mode-matching shadow-cache webhooks policy
avallete Aug 17, 2026
9baed89
fix(cli): validate restored shadow tars, canonicalize the API-grants …
avallete Aug 17, 2026
4d494f4
fix(cli): stamp and require a baseline marker in shadow snapshots
avallete Aug 17, 2026
b382f94
fix(cli): key-bind the snapshot marker, digest the Realtime seed cons…
avallete Aug 17, 2026
9134f2e
Merge remote-tracking branch 'origin/develop' into avallete/supabase-…
avallete Aug 18, 2026
5ca12af
test(cli): harden the shadow-cache live suite
avallete Aug 18, 2026
4ba00ac
test(cli): make the shadow-cache live suite a black-box CLI scenario
avallete Aug 18, 2026
9d27753
test(cli): derive the live suite's shadow-port candidates from the ru…
avallete Aug 18, 2026
f3dc609
docs(cli): log the image-tag-vs-digest cache-key accepted risk
avallete Aug 18, 2026
3dd25f3
Merge branch 'develop' into avallete/shadow-db-perf-6ad622
avallete Aug 19, 2026
7fd00b9
fix(cli): default the shadow baseline cache off for soak
avallete Aug 20, 2026
5f80832
fix(cli): drop pgjwt before pgcrypto on PG15+ declarative shadows
avallete Aug 21, 2026
29858c6
Merge remote-tracking branch 'origin/develop' into avallete/pr-6184-m…
avallete Aug 24, 2026
bb21b82
docs(cli): trim shadow-cache rationale comments per review
avallete Aug 24, 2026
3c8ac90
test(cli): create shadow-cache e2e drift via db query
avallete Aug 24, 2026
b997933
fix(cli): address shadow-cache review findings
avallete Aug 24, 2026
e31bb57
chore(cli): match archive problems exhaustively and reframe session c…
avallete Aug 24, 2026
ff17c99
chore(cli): reword lifecycle cleanup comment in its own terms
avallete Aug 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/cli-go/internal/db/declarative/declarative_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestWriteDeclarativeSchemas(t *testing.T) {

cfg, err := afero.ReadFile(fsys, utils.ConfigPath)
require.NoError(t, err)
assert.Contains(t, string(cfg), `"database"`)
assert.Contains(t, string(cfg), `"schemas"`)
}

func TestWriteDeclarativeSchemasSkipsConfigUpdateWhenPgDeltaEnabled(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion apps/cli-go/internal/utils/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ var (
CurrBranchPath = filepath.Join(SupabaseDirPath, ".branches", "_current_branch")
// DeclarativeDir is the canonical location for pg-delta declarative schema
// files generated or synced by `supabase db schema declarative` commands.
DeclarativeDir = filepath.Join(SupabaseDirPath, "database")
DeclarativeDir = filepath.Join(SupabaseDirPath, "schemas")
ClusterDir = filepath.Join(SupabaseDirPath, "cluster")
SchemasDir = filepath.Join(SupabaseDirPath, "schemas")
MigrationsDir = filepath.Join(SupabaseDirPath, "migrations")
Expand Down
2 changes: 1 addition & 1 deletion apps/cli-go/pkg/config/templates/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,6 @@ s3_secret_key = "env(S3_SECRET_KEY)"
[experimental.pgdelta]
enabled = {{ .Experimental.PgDeltaInitEnabled }}
# Directory under `supabase/` where declarative files are written.
# declarative_schema_path = "./database"
# declarative_schema_path = "./schemas"
# JSON string passed through to pg-delta SQL formatting.
# format_options = "{\"keywordCase\":\"upper\",\"indent\":2,\"maxWidth\":80,\"commaStyle\":\"trailing\"}"
3 changes: 2 additions & 1 deletion apps/cli/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,8 @@ Live tests are black-box CLI subprocess tests — like `*.e2e.test.ts`, but run
- **Where they run:** authored in this repo, but executed by the [`supabase/cli-e2e-ci`](https://github.com/supabase/cli-e2e-ci) harness, which builds this CLI, brings up a full supabox stack (and has a real Docker daemon, since that's how supabox itself runs), and invokes the `live` Vitest project (`nx run-many -t test:live`). They never run as part of the default unit/integration/e2e loop, and locally they no-op unless the live environment is configured (see below) — there is no need to stand up supabox yourself to develop other code.
- **Add one whenever you add or change a command whose correctness genuinely depends on a real backend** — a new Management API command, or a change to `start`/`stop`/`status`'s real Docker interaction. Colocate it with the command, same as `*.e2e.test.ts`: `src/legacy/commands/<command>/[<subcommand>/]<subcommand>.live.test.ts`.
- **Gating:** every live suite must be wrapped in one of `tests/helpers/live.ts`'s `describe.skipIf` gates so the file is inert (skipped, not failed) outside the cli-e2e-ci runner:
- `describeLive` — runs whenever `SUPABASE_ACCESS_TOKEN` is set (the live env is configured at all). Reuse this even for commands that don't call the Management API themselves (e.g. `stop`/`status`) — it doubles as the "we're in the full cli-e2e-ci runner, which also has a real Docker daemon" signal, and there is no dedicated Docker-availability gate today.
- `describeLive` — runs whenever `SUPABASE_ACCESS_TOKEN` is set (the live env is configured at all). Reuse this even for commands that don't call the Management API themselves (e.g. `stop`/`status`) — it doubles as the "we're in the full cli-e2e-ci runner, which also has a real Docker daemon" signal.
- `describeDockerLive` — the configured-live gate composed with a `docker info` probe; use for local-stack suites whose scenarios additionally need a reachable Docker daemon at collection time. It never runs on a machine that merely exposes Docker — `SUPABASE_ACCESS_TOKEN` must still be set, so the file stays inert outside the cli-e2e-ci runner like every other live suite.
- `describeLiveProject` — additionally requires a provisioned project (`SUPABASE_LIVE_PROJECT_REF`); use for project-scoped Management API commands (branches, functions, project-scoped db).
- `describeLiveDataPlane` — additionally requires the project's own Postgres instance to be `ACTIVE_HEALTHY`; use for commands that talk to the project's data plane (migration, db, storage).
- **Invocation:** use `runSupabaseLive(args, options?)` (wraps `runSupabase` with the `legacy` entrypoint and the live profile/timeout defaults) rather than calling `runSupabase` directly, so every live test picks up the same environment plumbing.
Expand Down
27 changes: 27 additions & 0 deletions apps/cli/docs/go-cli-divergences.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ These commands exist in the TS CLI today but have no direct top-level equivalent

## Flag divergences from the Go reference

- `db diff`, `db pull`, and `db schema declarative generate`/`sync` have a TS-only
`--strict-coverage` flag (no Go equivalent). It applies only when the bundled
pg-delta next engine is active (the default): coverage gaps that the engine
reports — statements it skipped or objects it could not represent — normally
surface as warnings, and `--strict-coverage` promotes them to hard failures.
Under the `SUPABASE_USE_PG_DELTA_NEXT=false` legacy opt-out the flag is
accepted but has no effect, since the legacy edge-runtime engine does not
emit coverage diagnostics. Default behavior (omitted flag) matches Go.
- `db push` has a TS-only `--skip-vault` flag. It applies migrations without
resolving or updating `[db.vault]` secrets; default behavior still matches Go.
- Every legacy command that resolves a linked project ref for its own database
Expand Down Expand Up @@ -71,6 +79,18 @@ These commands exist in the TS CLI today but have no direct top-level equivalent

## Behavioral divergences from the Go reference

- `db diff`/`db pull`/`db schema declarative sync` shadow baseline cache (#6184): the shadow
Comment thread
avallete marked this conversation as resolved.
Outdated
database's platform baseline is cached as a PGDATA snapshot under
`supabase/.temp/pgdelta/shadow-baseline-<key>.tar` (~90MB, current key only) and restored into a
fresh container on later runs, cutting shadow provisioning from ~15s to a few seconds. TS-only,
default ON; `SUPABASE_SHADOW_CACHE=false`/`=0` opts out (ambient env or project dotenv), `sync
--no-cache` bypasses it per-invocation, and `SUPABASE_SHADOW_DEBUG=1` prints stderr-only phase
timings. OrioleDB clusters and PG <= 14 are cache-ineligible (external S3 state and mid-session
role-default mutation respectively — see `shadow-cache.ts`). Known session-semantics caveat on
the cached paths: migrations run on a session opened after the baseline, so role-level defaults
a user's `roles.sql` installs (`ALTER ROLE … SET …`) apply to migrations, whereas Go's
Comment thread
avallete marked this conversation as resolved.
Outdated
single-connection flow ran migrations before those defaults took effect; opting out restores
Go's exact single-session behavior.
- `functions serve` per-function env discovery (CLI-2184, #6179): without `--env-file`, each
`supabase/functions/<function-name>/.env` overrides matching values from the shared
`supabase/functions/.env` for that Function only; an explicit `--env-file` remains the
Expand Down Expand Up @@ -151,3 +171,10 @@ These commands exist in the TS CLI today but have no direct top-level equivalent
redirect the service-role key to an attacker-controlled host. Intentional
TS-only hardening, not a parity bug — see
[`services/SIDE_EFFECTS.md`](../src/legacy/commands/services/SIDE_EFFECTS.md).
- `db pull` in-sync (`"No schema changes found"`) keeps Go's message and its non-zero
exit code, but replaces the generic "Try rerunning the command with --debug to
troubleshoot the error." stderr footer with an explanatory suggestion line
("The remote database is already in sync with your local migrations — nothing to
pull."). An in-sync database is a finding, not a failure to troubleshoot, so the
debug hint sent users chasing a non-existent bug. Message text and exit code — the
parts scripts depend on — are unchanged.
2 changes: 1 addition & 1 deletion apps/cli/docs/templates/examples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ supabase-db-schema-declarative-sync:
Reset local database to match migrations first? (local data will be lost) [y/N] y
Resetting database...
...
Declarative schema written to supabase/database
Declarative schema written to supabase/schemas
Finished supabase db schema declarative generate.
supabase-test-db:
- id: basic-usage
Expand Down
2 changes: 2 additions & 0 deletions apps/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@
"@parcel/watcher": "^2.6.0",
"@supabase/api": "workspace:*",
"@supabase/config": "workspace:*",
"@supabase/pg-delta": "1.0.0-alpha.40",
"@supabase/pg-topo": "1.0.0-alpha.5",
"@supabase/process-compose": "workspace:*",
"@supabase/stack": "workspace:*",
"@tsconfig/bun": "catalog:",
Expand Down
53 changes: 53 additions & 0 deletions apps/cli/scripts/build-binary.integration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { afterEach, describe, expect, test } from "vitest";
import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";

const fixturePath = fileURLToPath(
new URL("../tests/fixtures/compiled-libpg-query.ts", import.meta.url),
);
const temporaryDirectories: string[] = [];

afterEach(async () => {
await Promise.all(
temporaryDirectories.splice(0).map((directory) => rm(directory, { recursive: true })),
);
});

describe("compiled binary assets", () => {
test("embeds and loads libpg-query.wasm", async () => {
const directory = await mkdtemp(path.join(tmpdir(), "supabase-compiled-wasm-"));
temporaryDirectories.push(directory);
const executable = path.join(directory, "parser-probe");
const bunExecutable = Bun.which("bun");
if (!bunExecutable) {
throw new Error("Bun executable not found");
}

const build = Bun.spawn(
[bunExecutable, "build", fixturePath, "--compile", `--outfile=${executable}`],
{ stdout: "pipe", stderr: "pipe" },
);
const [buildExitCode, buildStderr] = await Promise.all([
build.exited,
new Response(build.stderr).text(),
]);
expect(buildExitCode, buildStderr).toBe(0);

const probe = Bun.spawn([executable], {
cwd: directory,
env: {},
stdout: "pipe",
stderr: "pipe",
});
const [probeExitCode, stdout, stderr] = await Promise.all([
probe.exited,
new Response(probe.stdout).text(),
new Response(probe.stderr).text(),
]);

expect(probeExitCode, stderr).toBe(0);
expect(stdout).toContain("libpg-query.wasm loaded");
}, 20_000);
});
Loading
Loading