Skip to content

chore(repo): sync develop into next - #7259

Closed
supabase-cli-releaser[bot] wants to merge 4 commits into
nextfrom
sync/develop-into-next
Closed

supabase-cli-releaser[bot] wants to merge 4 commits into
nextfrom
sync/develop-into-next

Conversation

@supabase-cli-releaser

Copy link
Copy Markdown
Contributor

Merging develop into next conflicts. This branch starts at the tip of develop (c24a92b); next is at 9914fc1.

Conflicting files:

  • apps/cli-go/cmd/db.go
  • apps/cli-go/cmd/root.go
  • apps/cli-go/cmd/root_test.go
  • apps/cli-go/internal/telemetry/project.go
  • apps/cli-go/internal/telemetry/project_test.go
  • apps/cli-go/internal/utils/flags/project_ref.go
  • apps/cli-go/internal/utils/flags/project_ref_test.go
  • apps/cli-go/pkg/config/config.go
  • apps/cli-go/pkg/config/config_test.go
  • apps/cli-go/pkg/config/utils.go
  • apps/cli/docs/go-cli-divergences.md
  • apps/cli/docs/go-cli-porting-status.md
  • apps/cli/docs/stack-commands.md
  • apps/cli/src/cli/complete.ts
  • apps/cli/src/cli/main.ts
  • apps/cli/src/cli/root.ts
  • apps/cli/src/command-internal/db-bootstrap/bootstrap-config.ts
  • apps/cli/src/command-internal/db-bootstrap/reset-local-database.ts
  • apps/cli/src/command-internal/db-config.integration.test.ts
  • apps/cli/src/command-internal/db-config.layer.ts
  • apps/cli/src/command-internal/db-config.service.ts
  • apps/cli/src/command-internal/db-config.toml-read.ts
  • apps/cli/src/command-internal/db-config.toml-read.unit.test.ts
  • apps/cli/src/command-internal/db-config.types.ts
  • apps/cli/src/command-internal/db-pull-run.ts
  • apps/cli/src/command-internal/go-proxy.layer.ts
  • apps/cli/src/command-internal/go-proxy.layer.unit.test.ts
  • apps/cli/src/command-internal/legacy-project-state.unit.test.ts
  • apps/cli/src/command-internal/link-services-core.ts
  • apps/cli/src/command-internal/linked-state.ts
  • apps/cli/src/command-internal/management-api-runtime.layer.ts
  • apps/cli/src/command-internal/parent-project-ref.ts
  • apps/cli/src/command-internal/pgdelta.paths.ts
  • apps/cli/src/command-internal/project-create-core.ts
  • apps/cli/src/command-internal/service-version-overrides.ts
  • apps/cli/src/command-internal/stack-backend.ts
  • apps/cli/src/command-internal/stack-config.ts
  • apps/cli/src/command-internal/temp-paths.unit.test.ts
  • apps/cli/src/command-internal/test-db.native.integration.test.ts
  • apps/cli/src/command-internal/upgrade-notice.integration.test.ts
  • apps/cli/src/command-internal/upgrade-notice.ts
  • apps/cli/src/commands/bootstrap/bootstrap.handler.ts
  • apps/cli/src/commands/bootstrap/bootstrap.integration.test.ts
  • apps/cli/src/commands/branches/list/list.handler.ts
  • apps/cli/src/commands/config/diff/diff.command.ts
  • apps/cli/src/commands/config/pull/pull.command.ts
  • apps/cli/src/commands/config/push/push.branch-target.ts
  • apps/cli/src/commands/config/push/push.command.ts
  • apps/cli/src/commands/config/push/push.handler.ts
  • apps/cli/src/commands/db/diff/SIDE_EFFECTS.md
  • apps/cli/src/commands/db/diff/diff.handler.ts
  • apps/cli/src/commands/db/dump/SIDE_EFFECTS.md
  • apps/cli/src/commands/db/pull/SIDE_EFFECTS.md
  • apps/cli/src/commands/db/pull/pull.integration.test.ts
  • apps/cli/src/commands/db/push/SIDE_EFFECTS.md
  • apps/cli/src/commands/db/push/push.handler.ts
  • apps/cli/src/commands/db/query/query.integration.test.ts
  • apps/cli/src/commands/db/remote/changes/SIDE_EFFECTS.md
  • apps/cli/src/commands/db/remote/changes/changes.handler.ts
  • apps/cli/src/commands/db/reset/SIDE_EFFECTS.md
  • apps/cli/src/commands/db/reset/reset.handler.ts
  • apps/cli/src/commands/db/reset/reset.integration.test.ts
  • apps/cli/src/commands/db/schema/declarative/declarative.orchestrate.integration.test.ts
  • apps/cli/src/commands/db/schema/declarative/generate/generate.handler.ts
  • apps/cli/src/commands/db/schema/declarative/sync/sync.handler.ts
  • apps/cli/src/commands/db/shared/pgdelta-engine.next.layer.integration.test.ts
  • apps/cli/src/commands/db/shared/pgdelta-next-shadow.stack.integration.test.ts
  • apps/cli/src/commands/domains/activate/activate.handler.ts
  • apps/cli/src/commands/domains/create/create.handler.ts
  • apps/cli/src/commands/domains/delete/delete.handler.ts
  • apps/cli/src/commands/domains/get/get.handler.ts
  • apps/cli/src/commands/domains/reverify/reverify.handler.ts
  • apps/cli/src/commands/experimental/stack/prepare/prepare.command.ts
  • apps/cli/src/commands/experimental/stack/prepare/prepare.integration.test.ts
  • apps/cli/src/commands/experimental/stack/stack-backend.integration.test.ts
  • apps/cli/src/commands/experimental/stack/stack-config-environment.integration.test.ts
  • apps/cli/src/commands/experimental/stack/stack-config.integration.test.ts
  • apps/cli/src/commands/experimental/stack/stack-forwarding.integration.test.ts
  • apps/cli/src/commands/experimental/stack/start/start.handler.ts
  • apps/cli/src/commands/experimental/stack/start/start.integration.test.ts
  • apps/cli/src/commands/experimental/stack/status/status.integration.test.ts
  • apps/cli/src/commands/feedback/add/add.integration.test.ts
  • apps/cli/src/commands/feedback/feedback-project-ref.ts
  • apps/cli/src/commands/functions/download/SIDE_EFFECTS.md
  • apps/cli/src/commands/functions/download/download.command.ts
  • apps/cli/src/commands/functions/download/download.handler.ts
  • apps/cli/src/commands/functions/serve/serve.stack.integration.test.ts
  • apps/cli/src/commands/gen/bearer-jwt/SIDE_EFFECTS.md
  • apps/cli/src/commands/gen/keys/SIDE_EFFECTS.md
  • apps/cli/src/commands/gen/keys/keys.handler.ts
  • apps/cli/src/commands/gen/types/SIDE_EFFECTS.md
  • apps/cli/src/commands/gen/types/types.handler.ts
  • apps/cli/src/commands/link/SIDE_EFFECTS.md
  • apps/cli/src/commands/link/link.handler.ts
  • apps/cli/src/commands/migration/list/list.integration.test.ts
  • apps/cli/src/commands/migration/repair/repair.integration.test.ts
  • apps/cli/src/commands/projects/api-keys/api-keys.handler.ts
  • apps/cli/src/commands/projects/list/list.handler.ts
  • apps/cli/src/commands/secrets/set/set.command.ts
  • apps/cli/src/commands/secrets/set/set.handler.ts
  • apps/cli/src/commands/secrets/unset/unset.handler.ts
  • apps/cli/src/commands/seed/buckets/buckets.integration.test.ts
  • apps/cli/src/commands/services/SIDE_EFFECTS.md
  • apps/cli/src/commands/services/services-local-stack.ts
  • apps/cli/src/commands/services/services.integration.test.ts
  • apps/cli/src/commands/sso/info/info.handler.ts
  • apps/cli/src/commands/status/status.integration.test.ts
  • apps/cli/src/commands/test/db/SIDE_EFFECTS.md
  • apps/cli/src/commands/unlink/SIDE_EFFECTS.md
  • apps/cli/src/commands/unlink/unlink.handler.ts
  • apps/cli/src/config/project-ref.layer.ts
  • apps/cli/src/config/project-ref.service.ts
  • apps/cli/src/config/remote-target.layer.unit.test.ts
  • apps/cli/src/shared/cli/hidden-flag.unit.test.ts
  • apps/cli/src/shared/config/temp-paths.ts
  • apps/cli/src/shared/config/temp-paths.unit.test.ts
  • apps/cli/src/telemetry/linked-project-cache.layer.ts
  • apps/cli/tests/helpers/command-mocks.ts
  • apps/cli/tests/helpers/storage.ts
  • packages/config/src/project-config/hosted-sections.ts

To resolve:

git fetch origin
git switch sync/develop-into-next
git merge origin/next
# resolve the conflicts, then commit
git push origin sync/develop-into-next

Approve to fast-forward next; do not use the merge button.

## Summary

Stack mode can now:

- run any service version that slim-services has published;
- match the hosted project's versions after `supabase link`;
- reproduce the whole local stack from one committed file,
`supabase/supabase.lock`.

Before this change, every service version was compiled into the CLI. You
couldn't try a hotfix, match production, or keep a team on the same
builds without everyone running the same CLI release.

Legacy (docker-compose) mode does not change, except for one fix: a
`SUPABASE_PROJECT_ID` naming another project than the linked one now
gets its pooler URL from the Management API, as `--project-ref` already
did, instead of reusing the linked project's saved
`supabase/.temp/pooler-url`. Everything below applies only to stack mode
(`SUPABASE_EXPERIMENTAL_STACK=1` or `[experimental] stack = true`).

> Version numbers and project refs in the examples are illustrative.

---

## The mental model: it works like a package manager

If you know `package.json` + `pnpm-lock.yaml`, or `Cargo.toml` +
`Cargo.lock`, you already know this.

| Package manager | Supabase stack mode | Committed? | Purpose |
| --- | --- | --- | --- |
| `package.json` | `[local.services]` in `supabase/config.toml` | ✅ |
What you **ask for**: `linked`, `bundled`, `v2.197.0`, `v2.197.0-r1` |
| `pnpm-lock.yaml` | `supabase/supabase.lock` | ✅ | What you **got**:
the exact build of every service, pinned by digest and checksum |
| — | `supabase/.link.json` | ❌ (gitignored) | Which hosted project or
branch *this checkout* targets |
| `pnpm install` | `supabase start` / `supabase stack install` | |
Resolves what changed, then runs or downloads the locked builds |
| `pnpm update` | `supabase stack update [svc…]` | | Re-resolves on
purpose and rewrites the lock |
| `pnpm outdated` | `supabase stack outdated` | | Read-only report of
what an update would change |
| `pnpm install --frozen-lockfile` | `supabase start --frozen` /
`supabase stack install --frozen` (implied when `CI` is set and a lock
exists) | | Fails instead of changing the lock |

```mermaid
flowchart LR
  subgraph git["Committed to git"]
    CFG["supabase/config.toml<br/>[local.services]<br/><i>what you ask for</i>"]
    LOCK["supabase/supabase.lock<br/><i>what you got</i>"]
  end
  subgraph checkout["This checkout only"]
    LINK["supabase/.link.json<br/><i>target hosted project</i>"]
  end
  HOSTED[("Hosted project")]
  RELEASES[("slim-services releases")]

  CFG -->|specifiers| START["supabase start<br/>stack install / stack update"]
  RELEASES -->|published builds + checksums| START
  START -->|writes when stale| LOCK
  HOSTED -->|versions it runs| LINKCMD["supabase link"]
  LINKCMD --> LINK
  LINKCMD -->|records observations,<br/>resolves 'linked'| LOCK
  LOCK -->|exact pins| STACK[("Local stack")]
```

---

## How a version is asked for

```toml
[local.services]
default = { version = "linked" }  # the default: follow the linked hosted project

[local.services.auth]
version = "v2.197.0"              # an upstream version: its highest published revision

[local.services.realtime]
version = "v2.144.2-r1"           # exactly revision 1 of that upstream version
```

`bundled` means "the version this CLI ships with". `[db]
orioledb_version` is shorthand for the database specifier, and a
database version must match `db.major_version`.

```mermaid
flowchart TD
  SPEC["specifier of a service"] --> KIND{"which kind?"}
  KIND -->|"linked (default)"| LINKED{"is the project linked,<br/>and does it report a version?"}
  LINKED -->|never linked| B1["bundled pin<br/>unlinked"]
  LINKED -->|service not reported| B2["bundled pin<br/>unobserved"]
  LINKED -->|reported| PUB{"published by<br/>slim-services?"}
  PUB -->|no| B3["bundled pin<br/>unpublished"]
  PUB -->|yes| R1["the hosted release<br/>resolved"]
  KIND -->|bundled| R2["this CLI's bundled pin"]
  KIND -->|"v2.197.0"| R3["highest published revision<br/>of v2.197.0"]
  KIND -->|"v2.197.0-r1"| R4["exactly v2.197.0-r1"]
```

The fallback reasons (`unlinked`, `unobserved`, `unpublished`) are
recorded in the lock, so nobody has to guess why a service isn't running
the hosted version.

## What the lock contains

One entry per service (database, rest, auth, realtime, storage,
imgproxy, functions, studio, pgmeta, mail, analytics, pooler). Keys are
sorted and the document is written atomically, so diffs and merge
conflicts stay readable.

```jsonc
{
  "$schema": "https://supabase.com/docs/cli/supabase-lock/v1.schema.json",
  "lockfileVersion": 1,
  "linked": {                                   // the remote the observations came from
    "project": "abcdefghijklmnopqrst",
    "branch": { "ref": "abcdefghijklmnopqrst", "isDefault": true },
    "observedAt": "2026-10-16T09:12:44.000Z"
  },
  "services": {
    "auth": {
      "specifier": "linked",                    // what config.toml asked for
      "linked": { "raw": "v2.196.1", "version": "v2.196.1" },  // what the hosted project reported
      "resolution": "resolved",                 // or unlinked / unobserved / unpublished
      "resolved": {                             // the exact build that runs
        "upstreamVersion": "v2.196.1",
        "revision": 0,
        "upstreamImage": "supabase/gotrue:v2.196.1",
        "image": "ghcr.io/supabase/cli/gotrue:v2.196.1-r0@sha256:…",
        "natives": { "darwin-arm64": { "archive": "…", "manifest": "…" }, "…": {} }
      }
    },
    "database": { "majorVersion": 17, "line": "stock", "…": "…" }
    // …one entry per service
  }
}
```

---

## What `supabase start` does with the lock

```mermaid
flowchart TD
  S["supabase start"] --> FRESH{"lock exists, and every entry<br/>still matches config.toml?"}
  FRESH -->|yes| RUN["run the locked builds<br/>(no network, no Management API)"]
  FRESH -->|"no (missing or stale)"| FROZEN{"frozen?<br/>--frozen, or CI with a lock"}
  FROZEN -->|yes| FAIL["fail: lock missing or stale<br/>→ run supabase start locally and commit it"]
  FROZEN -->|no| LEASE["take the project lease<br/>(serializes concurrent starts)"]
  LEASE --> RESOLVE["re-resolve only the services<br/>whose specifier changed"]
  RESOLVE --> WRITE["write supabase.lock atomically"]
  WRITE --> RUN
```

A start never calls the Management API and needs no login. It only warns
when:

- `.link.json` targets another project or branch than the lock observed
(run `supabase stack update`);
- this CLI bundles a newer revision of a locked version.

---

## Typical workflows

### 1. New project, never linked

```console
$ supabase start
Resolved service versions:
  database  17.11.0.004-r0  (specifier linked; unlinked)
  auth      v2.197.0-r0  (specifier linked; unlinked)
  realtime  v2.144.2-r0  (specifier linked; unlinked)
  …
Created supabase/supabase.lock.
```

Nothing is linked yet, so `linked` falls back to the bundled builds and
says so. Commit `supabase/supabase.lock`, and every teammate and CI job
now runs exactly these builds, whatever CLI version they have.

### 2. Match production: `supabase link`

```console
$ supabase link --project-ref abcdefghijklmnopqrst
Hosted versions:
  service   hosted       locked          resolution
  database  17.6.1.011   17.6.1.011-r0   resolved
  auth      v2.196.1     v2.196.1-r0     resolved
  realtime  v2.143.0     v2.143.0-r2     resolved
  studio    -            2026.10.12-…    unobserved
  …
Updated supabase/supabase.lock: now observing abcdefghijklmnopqrst (5 version changes). Review and commit it.
Finished supabase link.
```

`link` probes the hosted project, or the branch, and records what it
runs. Every `linked` service moves to that release. `link` writes
`.link.json` and the lock together, under the same project lease as
`start`. The next `supabase start` runs the hosted versions.

Linking a preview branch works the same way. The lock records which
project and branch it observed, so `start` warns if the checkout's link
later points elsewhere.

### 3. Try one specific version, or a hotfix revision

```toml
[local.services.auth]
version = "v2.198.0"
```

```console
$ supabase start
Resolved service versions:
  auth      v2.196.1-r0 → v2.198.0-r0  (specifier v2.198.0 ≠ locked linked)
Updated supabase/supabase.lock.
```

Only the changed entry is re-resolved, and every other pin stays where
it was. Remove the override to go back to `linked`. Pinning
`v2.198.0-r1` selects exactly that revision.

### 4. A teammate clones the repo, and CI

```console
$ git clone … && cd my-app
$ supabase start          # the lock is fresh: runs the committed builds, no resolution
```

In CI (`CI` set and a lock present), `start`, `stack install` and `link`
are frozen: a stale or missing lock fails instead of being rewritten.

```console
$ CI=1 supabase start
supabase/supabase.lock is stale for: auth (specifier v2.198.0 ≠ locked linked); run supabase start locally and commit the updated lock
```

`supabase stack install --frozen --runtime native` downloads everything
the lock pins without creating a stack, which makes it handy as a cached
CI warm-up step.

### 5. Upgrading the CLI

Upgrading never changes locked versions. If the new CLI bundles a newer
revision of a version you locked, `start` mentions it:

```console
$ supabase start
This CLI bundles newer revisions of locked versions: realtime v2.144.2-r0 → v2.144.2-r1. Run supabase stack outdated to review, supabase stack update to adopt them.
```

```console
$ supabase stack outdated
   SERVICE  | SPECIFIER | HOSTED   | LOCKED      | UPDATE      | BUNDLED     | STATUS           
  ----------|-----------|----------|-------------|-------------|-------------|------------------
   auth     | linked    | v2.196.1 | v2.196.1-r0 | -           | v2.197.0-r0 | up to date       
   realtime | bundled   | -        | v2.144.2-r0 | v2.144.2-r1 | v2.144.2-r1 | update available 
   …
Run supabase stack update to adopt the updates.

$ supabase stack update realtime     # or no argument for every service
```

`stack outdated` is read-only. `stack update` re-resolves the named
services even when the lock is fresh:

- an upstream version moves to its newest revision;
- `bundled` moves to the version this CLI bundles;
- `linked` probes the hosted project again;
- an exact `-rN` pin stays.

### 6. Unlinking

`supabase unlink` removes `.link.json` and the stored credential under
the project lease. The lock is not touched: it stays a valid, reviewed
lock, and its `linked` entry still shows where the observations came
from.

---

## Your local data is protected when versions change

Changing a version must never silently corrupt a local database.

| Change | What happens |
| --- | --- |
| A new revision of the same database build | Accepted |
| Any other database build (another upstream version or Postgres major,
or switching between stock and OrioleDB) with initialized data |
Refused. The advice offers pinning the recorded build under
`[local.services.database]` to keep the data (setting `[db]
major_version` back or removing `[db] orioledb_version` where they would
conflict with that pin), or `supabase stack destroy --stack-id …` (this
deletes the local data) |
| The same change on a database that never initialized | Adopted |
| Moving auth, storage or realtime **back** to a version older than one
that already migrated this database | Refused: a downgrade doesn't
restore the old schema |

`link` and `stack update` still move `linked` pins, but they warn when a
saved stack's data would refuse the new pins.

The database records the build that initialized it. Each schema-owning
service records the newest version that migrated it. Snapshots, restores
and `db reset` carry and respect both records.

---

## Stack mode no longer uses `supabase/.temp`

| Before (`supabase/.temp`) | Now in stack mode |
| --- | --- |
| Project ref, pooler URL, branch | `supabase/.link.json` (gitignored) |
| Postgres and edge-runtime versions | `supabase/supabase.lock` |
| Storage uploads | `$SUPABASE_HOME/stacks/<id>/uploads`, removed by
`stack destroy` |
| Scratch files (pgdelta debug bundles, Functions bundling) |
`$SUPABASE_HOME/tmp` |
| Release-check cache | `$SUPABASE_HOME/cli-latest` |

Delegated Go commands skip `.temp` too. Remote commands resolve the
hosted target once per command, in this order:

1. the `--project-ref` flag;
2. `SUPABASE_PROJECT_ID`;
3. the link;
4. the interactive picker.

Three commands change with this beyond the `.temp` move:

- `gen keys` resolves its project this way, picker included, and passes
it to the delegated command;
- the upgrade notice picks its release-check cache by the project's
mode, read from the working directory it was handed;
- `db pull` builds its shadow database from the locked pins, falling
back to the bundled database pin of the major a `[remotes]` block
selects.

`supabase stack install` replaces the experimental `supabase stack
prepare`.

---

## Reading this PR

There is one commit per chunk, in dependency order; each builds on the
previous one.

| Commit | What it adds |
| --- | --- |
| `docs(stack)` | ADRs 0026 and 0017: the lock-based version model |
| `feat(config)` | `[local.services]` specifiers in the config schema |
| `feat(stack)` resolve pins | Resolving slim-services releases with
checksum, manifest and provenance verification |
| `refactor(cli)` `.temp` layout | One owner for every legacy `.temp`
path |
| `feat(stack)` explicit pin | Every service creation carries the exact
pin it runs |
| `feat(cli)` `.link.json` | The hosted link file in stack mode |
| `feat(stack)` lock format | The `supabase.lock` schema, deterministic
write, typed read errors |
| `feat(stack)` test stacks | `@supabase/stack` test stacks run the
project lock |
| `feat(stack)` database build guard | Initialized data is tied to its
build |
| `feat(cli)` hosted target | One hosted-target resolution per command |
| `feat(stack)` schema writers | Refuses older schema writers on
migrated databases |
| `feat(cli)` lock at start | Resolve and lock at `start`; `--frozen`
and CI behavior |
| `feat(cli)` install | `stack install`, `stack prepare` removed |
| `feat(cli)` update/outdated | `stack update` and `stack outdated` |
| `feat(cli)` linked versions | `link` observes hosted versions and
resolves `linked` |
| `feat(cli)` no `.temp` | Stack mode leaves `supabase/.temp` alone |
| `feat(cli)` Go off `.temp` | Delegated Go commands do the same |
| `test(cli)` | Explicit timeouts on owner-spawning destroy tests |

Review fixes and merges from `develop` follow these commits.

User-facing reference:
[`apps/cli/docs/stack-commands.md`](https://github.com/supabase/cli/blob/juliengoux/cli-2688-stack-mode-lockable-service-versions-with-hosted-parity-via/apps/cli/docs/stack-commands.md#service-versions)
and the [`start` side
effects](https://github.com/supabase/cli/blob/juliengoux/cli-2688-stack-mode-lockable-service-versions-with-hosted-parity-via/apps/cli/src/commands/experimental/stack/start/SIDE_EFFECTS.md#service-versions-and-the-lock).

---------

Co-authored-by: Colum Ferry <cferry09@gmail.com>
@supabase-cli-releaser
supabase-cli-releaser Bot requested review from a team and supabase-oss as code owners October 20, 2026 10:18
@supabase-cli-releaser supabase-cli-releaser Bot added the do not merge Approve to apply; do not merge. label Oct 20, 2026
# Conflicts:
#	apps/cli-go/cmd/db.go
#	apps/cli-go/cmd/root.go
#	apps/cli-go/cmd/root_test.go
#	apps/cli-go/internal/telemetry/project.go
#	apps/cli-go/internal/telemetry/project_test.go
#	apps/cli-go/internal/utils/flags/project_ref.go
#	apps/cli-go/internal/utils/flags/project_ref_test.go
#	apps/cli-go/pkg/config/config.go
#	apps/cli-go/pkg/config/config_test.go
#	apps/cli-go/pkg/config/utils.go
#	apps/cli/docs/go-cli-divergences.md
#	apps/cli/docs/go-cli-porting-status.md
#	apps/cli/docs/stack-commands.md
#	apps/cli/src/cli/complete.ts
#	apps/cli/src/cli/main.ts
#	apps/cli/src/cli/root.ts
#	apps/cli/src/command-internal/db-bootstrap/bootstrap-config.ts
#	apps/cli/src/command-internal/db-bootstrap/reset-local-database.ts
#	apps/cli/src/command-internal/db-config.integration.test.ts
#	apps/cli/src/command-internal/db-config.layer.ts
#	apps/cli/src/command-internal/db-config.service.ts
#	apps/cli/src/command-internal/db-config.toml-read.ts
#	apps/cli/src/command-internal/db-config.toml-read.unit.test.ts
#	apps/cli/src/command-internal/db-config.types.ts
#	apps/cli/src/command-internal/db-pull-run.ts
#	apps/cli/src/command-internal/go-proxy.layer.ts
#	apps/cli/src/command-internal/go-proxy.layer.unit.test.ts
#	apps/cli/src/command-internal/legacy-project-state.unit.test.ts
#	apps/cli/src/command-internal/link-services-core.ts
#	apps/cli/src/command-internal/linked-state.ts
#	apps/cli/src/command-internal/management-api-runtime.layer.ts
#	apps/cli/src/command-internal/parent-project-ref.ts
#	apps/cli/src/command-internal/pgdelta.paths.ts
#	apps/cli/src/command-internal/project-create-core.ts
#	apps/cli/src/command-internal/service-version-overrides.ts
#	apps/cli/src/command-internal/stack-backend.ts
#	apps/cli/src/command-internal/stack-config.ts
#	apps/cli/src/command-internal/temp-paths.unit.test.ts
#	apps/cli/src/command-internal/test-db.native.integration.test.ts
#	apps/cli/src/command-internal/upgrade-notice.integration.test.ts
#	apps/cli/src/command-internal/upgrade-notice.ts
#	apps/cli/src/commands/bootstrap/bootstrap.handler.ts
#	apps/cli/src/commands/bootstrap/bootstrap.integration.test.ts
#	apps/cli/src/commands/branches/list/list.handler.ts
#	apps/cli/src/commands/config/diff/diff.command.ts
#	apps/cli/src/commands/config/pull/pull.command.ts
#	apps/cli/src/commands/config/push/push.branch-target.ts
#	apps/cli/src/commands/config/push/push.command.ts
#	apps/cli/src/commands/config/push/push.handler.ts
#	apps/cli/src/commands/db/diff/SIDE_EFFECTS.md
#	apps/cli/src/commands/db/diff/diff.handler.ts
#	apps/cli/src/commands/db/dump/SIDE_EFFECTS.md
#	apps/cli/src/commands/db/pull/SIDE_EFFECTS.md
#	apps/cli/src/commands/db/pull/pull.integration.test.ts
#	apps/cli/src/commands/db/push/SIDE_EFFECTS.md
#	apps/cli/src/commands/db/push/push.handler.ts
#	apps/cli/src/commands/db/query/query.integration.test.ts
#	apps/cli/src/commands/db/remote/changes/SIDE_EFFECTS.md
#	apps/cli/src/commands/db/remote/changes/changes.handler.ts
#	apps/cli/src/commands/db/reset/SIDE_EFFECTS.md
#	apps/cli/src/commands/db/reset/reset.handler.ts
#	apps/cli/src/commands/db/reset/reset.integration.test.ts
#	apps/cli/src/commands/db/schema/declarative/declarative.orchestrate.integration.test.ts
#	apps/cli/src/commands/db/schema/declarative/generate/generate.handler.ts
#	apps/cli/src/commands/db/schema/declarative/sync/sync.handler.ts
#	apps/cli/src/commands/db/shared/pgdelta-engine.next.layer.integration.test.ts
#	apps/cli/src/commands/db/shared/pgdelta-next-shadow.stack.integration.test.ts
#	apps/cli/src/commands/domains/activate/activate.handler.ts
#	apps/cli/src/commands/domains/create/create.handler.ts
#	apps/cli/src/commands/domains/delete/delete.handler.ts
#	apps/cli/src/commands/domains/get/get.handler.ts
#	apps/cli/src/commands/domains/reverify/reverify.handler.ts
#	apps/cli/src/commands/experimental/stack/prepare/prepare.command.ts
#	apps/cli/src/commands/experimental/stack/prepare/prepare.integration.test.ts
#	apps/cli/src/commands/experimental/stack/stack-backend.integration.test.ts
#	apps/cli/src/commands/experimental/stack/stack-config-environment.integration.test.ts
#	apps/cli/src/commands/experimental/stack/stack-config.integration.test.ts
#	apps/cli/src/commands/experimental/stack/stack-forwarding.integration.test.ts
#	apps/cli/src/commands/experimental/stack/start/start.handler.ts
#	apps/cli/src/commands/experimental/stack/start/start.integration.test.ts
#	apps/cli/src/commands/experimental/stack/status/status.integration.test.ts
#	apps/cli/src/commands/feedback/add/add.integration.test.ts
#	apps/cli/src/commands/feedback/feedback-project-ref.ts
#	apps/cli/src/commands/functions/download/SIDE_EFFECTS.md
#	apps/cli/src/commands/functions/download/download.command.ts
#	apps/cli/src/commands/functions/download/download.handler.ts
#	apps/cli/src/commands/functions/serve/serve.stack.integration.test.ts
#	apps/cli/src/commands/gen/bearer-jwt/SIDE_EFFECTS.md
#	apps/cli/src/commands/gen/keys/SIDE_EFFECTS.md
#	apps/cli/src/commands/gen/keys/keys.handler.ts
#	apps/cli/src/commands/gen/types/SIDE_EFFECTS.md
#	apps/cli/src/commands/gen/types/types.handler.ts
#	apps/cli/src/commands/link/SIDE_EFFECTS.md
#	apps/cli/src/commands/link/link.handler.ts
#	apps/cli/src/commands/migration/list/list.integration.test.ts
#	apps/cli/src/commands/migration/repair/repair.integration.test.ts
#	apps/cli/src/commands/projects/api-keys/api-keys.handler.ts
#	apps/cli/src/commands/projects/list/list.handler.ts
#	apps/cli/src/commands/secrets/set/set.command.ts
#	apps/cli/src/commands/secrets/set/set.handler.ts
#	apps/cli/src/commands/secrets/unset/unset.handler.ts
#	apps/cli/src/commands/seed/buckets/buckets.integration.test.ts
#	apps/cli/src/commands/services/SIDE_EFFECTS.md
#	apps/cli/src/commands/services/services-local-stack.ts
#	apps/cli/src/commands/services/services.integration.test.ts
#	apps/cli/src/commands/sso/info/info.handler.ts
#	apps/cli/src/commands/status/status.integration.test.ts
#	apps/cli/src/commands/test/db/SIDE_EFFECTS.md
#	apps/cli/src/commands/unlink/SIDE_EFFECTS.md
#	apps/cli/src/commands/unlink/unlink.handler.ts
#	apps/cli/src/config/project-ref.layer.ts
#	apps/cli/src/config/project-ref.service.ts
#	apps/cli/src/config/remote-target.layer.unit.test.ts
#	apps/cli/src/shared/cli/hidden-flag.unit.test.ts
#	apps/cli/src/shared/config/temp-paths.ts
#	apps/cli/src/shared/config/temp-paths.unit.test.ts
#	apps/cli/src/telemetry/linked-project-cache.layer.ts
#	apps/cli/tests/helpers/command-mocks.ts
#	apps/cli/tests/helpers/storage.ts
#	packages/config/src/project-config/hosted-sections.ts
@supabase-cli-releaser

Copy link
Copy Markdown
Contributor Author

Claude resolved the merge of next

All conflicted files are resolved and no conflict markers remain. Nothing has been type-checked or tested yet, so the job's check:all and unit tests are the first real check. The resolution keeps develop's LegacyProjectState/RemoteTarget/.link.json design in place of next's moved temp-paths and ProjectRefResolver, and keeps next's breaking changes: the Go CLI is removed, deprecated commands become tombstones, --include-raw-output is gone, and config values go through CliConfigValues. Import scans across apps/cli/src and packages/* found no broken relative imports, though some of them ran while files still had markers.

File Resolution
apps/cli/src/cli/main.ts Keeps develop's project-state selection and next's config provider layer; projectStateMode is now called without env.
apps/cli/src/cli/root.ts Takes next's side, which removes the GoProxy layer; develop's projectStateModeLayer wiring is kept.
apps/cli/src/cli/complete.ts Imports parse-uint from next's shared/config location and keeps develop's ProjectStateMode import.
apps/cli/src/command-internal/upgrade-notice.ts Uses next's hook without delegatedToGo, plus develop's legacy-state check. The mode is read from the success workdir by passing it as --workdir in args.
apps/cli/src/command-internal/upgrade-notice.integration.test.ts Drops delegatedToGo and keeps develop's workingDirectory option.
apps/cli/src/shared/cli/hidden-flag.unit.test.ts Merges the imports: develop's legacyProjectStateLayer and next's Option and Stdio.
apps/cli/src/command-internal/project-state-mode.ts Semantic fix: removed the env input, because next removed it from the experimental-feature helpers.
apps/cli/src/command-internal/stack-backend.ts Keeps develop's usesStackState and resolveProjectStateSelection, with next's {args, cwd} input.
apps/cli/src/command-internal/stack-config.ts loadStackConfig accepts develop's context/selection/frozen/publishesLock options plus next's projectRef, and loads config through CliConfigValues unless a context is passed.
apps/cli/src/command-internal/service-version-overrides.ts Uses develop's legacyProjectStatePaths and usesStackState.
apps/cli/src/commands/experimental/stack/start/start.handler.ts Develop's lock helpers and cached start config, fed into next's configBeforeCreate/replan flow.
apps/cli/src/commands/experimental/stack/install/install.command.ts Gains next's cliConfigValuesLayer and withCliConfigFlags wiring from the deleted prepare command.
apps/cli/src/commands/experimental/stack/update/update.command.ts Semantic fix: provides cliConfigValuesLayer, which its handler now needs.
apps/cli/src/commands/experimental/stack/outdated/outdated.command.ts Semantic fix: adds an empty flag config and provides cliConfigValuesLayer, for the same reason as update.
apps/cli/src/commands/services/services-local-stack.ts Next's config-value error handling with develop's lock-selection fallback.
apps/cli/src/command-internal/db-config.toml-read.ts Next's CliConfigValues version. poolerConnectionString is removed because the saved pooler URL now comes only from develop's RemoteTarget.poolerUrl.
apps/cli/src/command-internal/testdata/config-precedence/db-toml/*.json Removed the poolerConnectionString line from all 14 snapshot files to match.
apps/cli/src/command-internal/db-config.layer.ts Keeps both develop's poolerUrl handling and next's hasPasswordFlag.
apps/cli/src/command-internal/db-config.service.ts Uses develop's LinkedProjectRefReadError.
apps/cli/src/command-internal/db-config.types.ts Next's meaning for adHocProjectRef with develop's 'saved pooler URL' wording.
apps/cli/src/commands/bootstrap/bootstrap.handler.ts Develop's stack/legacy-mode structure, with next's linked DB password key, project .env loading, writeThrough wrapping and seed input ported in.
apps/cli/src/commands/link/link.handler.ts Develop's structure, with next's writeThrough cache invalidation applied to develop's state writes.
apps/cli/src/command-internal/management-api-runtime.layer.ts RemoteTarget and remoteTargetLayer, with DebugLogger imported from next's new location.
apps/cli/src/commands/functions/download/download.handler.ts Drops the Go proxy download path for the removed --legacy-bundle and uses remoteTarget.resolve(...).ref.
apps/cli/src/commands/domains/{activate,create,delete,get,reverify}/*.handler.ts Drops warnIncludeRawOutputDeprecated (removed on next) and keeps develop's { ref } destructuring.
apps/cli/src/commands/{config,secrets,sso,projects,branches,gen,db}/** handlers and commands Develop's RemoteTarget and legacy-state imports combined with next's CliConfigValues, withCliConfigFlags, outputFlag and encoder changes.
apps/cli/src/command-internal/{linked-state,parent-project-ref,link-services-core,db-pull-run,pgdelta.paths,project-create-core}.ts and telemetry/linked-project-cache.layer.ts Keep develop's link-snapshot and legacy-state APIs with next's other edits.
apps/cli/src/command-internal/legacy-project-state.unit.test.ts Develop's tests, rewritten in next's test-helper style.
apps/cli/src/config/cli-config-values.layer.ts Semantic fix: reads the linked ref through develop's mode-aware readLinkSnapshot.
apps/cli/src/config/cli-config-values.service.ts Semantic fix: the error union now uses LinkedProjectRefReadError.
apps/cli/src/command-internal/db-bootstrap/db-setup.ts Semantic fix: the error union now uses LinkedProjectRefReadError.
apps/cli/src/config/cli-config-remote.ts Semantic fix: PROJECT_REF_PATTERN is now imported from remote-target.service.ts.
apps/cli/src/commands/db/pull/pull.removed-flag.integration.test.ts Semantic fix: PROJECT_NOT_LINKED_MESSAGE is now imported from remote-target.service.ts.
apps/cli/tests/helpers/{storage,command-mocks}.ts and integration tests Test layers combine develop's RemoteTarget, legacy-state and project-state-mode layers with next's cliConfigValuesTestLayer, withConfigEnv and outputFlag.
apps/cli/src/commands/**/SIDE_EFFECTS.md and apps/cli/docs/stack-commands.md Next's prose and removals with RemoteTarget wording, plus develop's stack-mode, lock and pooler-URL notes.
packages/config/src/project-config/hosted-sections.ts Next's comment wording plus develop's mention of the top-level local section.
.github/scripts/flaky-check/{plan.ts,plan.test.ts,cli.ts} Semantic fix: removed the cli-go turbo filter and the SUPABASE_GO_BINARY setup, since next deleted the Go CLI.

Deleted: apps/cli-go/cmd/db.go, apps/cli-go/cmd/root.go, apps/cli-go/cmd/root_test.go, apps/cli-go/internal/telemetry/project.go, apps/cli-go/internal/telemetry/project_test.go, apps/cli-go/internal/utils/flags/project_ref.go, apps/cli-go/internal/utils/flags/project_ref_test.go, apps/cli-go/pkg/config/config.go, apps/cli-go/pkg/config/config_test.go, apps/cli-go/pkg/config/utils.go, apps/cli/docs/go-cli-divergences.md, apps/cli/docs/go-cli-porting-status.md, apps/cli/src/command-internal/go-proxy.layer.ts, apps/cli/src/command-internal/go-proxy.layer.unit.test.ts, apps/cli/src/commands/db/remote/changes/changes.handler.ts, apps/cli/src/commands/gen/keys/keys.handler.ts, apps/cli/src/command-internal/temp-paths.unit.test.ts, apps/cli/src/shared/config/temp-paths.ts, apps/cli/src/shared/config/temp-paths.unit.test.ts, apps/cli/src/config/project-ref.layer.ts, apps/cli/src/config/project-ref.service.ts, apps/cli/src/commands/experimental/stack/prepare/prepare.command.ts, apps/cli/src/commands/experimental/stack/prepare/prepare.integration.test.ts.

Decisions for @supabase/cli. Confirm them, or push a change to this branch:

  • temp-paths: next moved it to shared/config, while develop replaced it with legacy-project-state/link-snapshot/project-link Chose: Keep develop's replacement and delete next's shared/config/temp-paths.ts and its test. Code that only next has is switched to readLinkSnapshot or LinkedProjectRefReadError.
  • ProjectRefResolver (next) vs RemoteTarget (develop) Chose: Keep develop's RemoteTarget and delete project-ref.service.ts and project-ref.layer.ts. project-ref.errors.ts stays because it is still imported.
  • Where the saved pooler URL comes from: next's db config field vs develop's link snapshot Chose: Remove DbTomlValues.poolerConnectionString and use develop's RemoteTarget.poolerUrl as the only source.
  • Ad-hoc project ref and the ambient SUPABASE_DB_PASSWORD Chose: Follow next: CliConfigValues holds the password back with a warning.
  • stack prepare: develop replaced it with stack install, while next modified prepare Chose: Delete prepare and port next's config wiring onto install; update and outdated get the same wiring.
  • Go delegation code and docs develop modified Chose: Delete them, because next removed the Go CLI under ADR 0031.
  • projectStateMode env input (develop) vs next's removal of explicit env Chose: Drop env. upgrade-notice passes the success workdir as --workdir so it still decides the mode.
  • loadStackConfig shape: develop's lock options vs next's CliConfigValues loading Chose: Accept both: a passed context is reused, otherwise config loads through CliConfigValues.

Quick checks. pnpm run check:all --continue (exit 1), pnpm run test:unit (exit 1) failed on the merged tree.

Claude's fix. Fixed the merge's semantic conflicts. Next's CliConfigValues service is now provided to develop's stack-mode tests: seedLock, update, outdated, link lock/stack-mode, deploy, download and stack-shadow. The removed LocalProjectContext.loaded is replaced with resolvedConfig.hasConfigFile/appliedRemote in link.handler.ts, stack-shadow.ts and its test. The registry now treats develop's local.services.<service>.version keys as optional and gates each one on its own local.services.<service> section. The unused SUPABASE_EXPERIMENTAL_STACK read is gone from the upgrade notice, and the config layer's import of develop's link reader is recorded as an exception in both ADR 0032 and the code-structure guard. Still needs a maintainer: delete apps/cli/src/command-internal/go-proxy-target-env.ts, its integration test and the remoteTargetRuntimeLayer export only they use. They target the Go proxy and the db remote changes/gen keys handlers that next removed, and I am not allowed to delete files; they are behind the SUPABASE_INTERNAL_POOLER_URL unit failure and likely part of the knip and tsc failures. The CI log showed only the end of the tsc output, so I checked every relative import and test-helper symbol: that test file is the only one that imports missing files.

Approve to fast-forward next once checks pass (workflow run).

@supabase-cli-releaser supabase-cli-releaser Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Workflow changes for a maintainer

Claude's edits under .github/ are not pushed, because workflows on this branch run with repository secrets. Review them, then use Commit suggestions so they run.

Apply these by hand:

diff --git a/.github/scripts/flaky-check/cli.ts b/.github/scripts/flaky-check/cli.ts
index 979fa17b7..0079bda6e 100644
--- a/.github/scripts/flaky-check/cli.ts
+++ b/.github/scripts/flaky-check/cli.ts
@@ -115,3 +114,0 @@ async function runCommand(): Promise<number> {
-  if (entry.suite === "e2e") {
-    process.env.SUPABASE_GO_BINARY = join(process.cwd(), "apps/cli-go/supabase-go");
-  }
diff --git a/.github/scripts/flaky-check/plan.test.ts b/.github/scripts/flaky-check/plan.test.ts
index 83c752ecb..0a963da7b 100644
--- a/.github/scripts/flaky-check/plan.test.ts
+++ b/.github/scripts/flaky-check/plan.test.ts
@@ -104,4 +104 @@ describe("commandsFor", () => {
-      [
-        { turbo: ["test:unit:run", "--filter=!@supabase/cli-go"], report: "unit.3" },
-        ".flaky-results/unit.3.json",
-      ],
+      [{ turbo: ["test:unit:run"], report: "unit.3" }, ".flaky-results/unit.3.json"],
diff --git a/.github/scripts/flaky-check/plan.ts b/.github/scripts/flaky-check/plan.ts
index df37d4e70..e30f5a44c 100644
--- a/.github/scripts/flaky-check/plan.ts
+++ b/.github/scripts/flaky-check/plan.ts
@@ -221,6 +221 @@ function unit(iteration: number, extra: string[]): Invocation[] {
-  return [
-    turbo(["test:unit:run", "--filter=!@supabase/cli-go"], `unit.${iteration}`, [
-      "--passWithNoTests",
-      ...extra,
-    ]),
-  ];
+  return [turbo(["test:unit:run"], `unit.${iteration}`, ["--passWithNoTests", ...extra])];

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI Review

Verified all five findings against the checked-out code and sync-resolution diff, merging duplicates into three confirmed findings: broken integration-test imports, a helper orphaned by the merge resolutions, and a stray temporary file. Tests were not run because dependencies are absent.

Findings

Severity Location Category Sources Claim
🟠 MAJOR apps/cli/src/command-internal/go-proxy-target-env.integration.test.ts:18 merge-resolution claude+codex The retained integration suite imports three deleted modules, preventing it from loading and breaking the integration test run and typechecking.
🟡 MINOR apps/cli/src/command-internal/go-proxy-target-env.ts:25 merge-resolution claude The merge resolutions remove both callers of goProjectTarget but retain its implementation, leaving an unused helper for the removed Go-delegation path.
⚪ NIT apps/cli/src/commands/functions/download/SIDE_EFFECTS.md.tmp-unused:1 merge-resolution claude+codex The merge resolution adds a stray temporary file containing only the character x.

Stats

Claude findings: 3 · Codex findings: 2 · Confirmed: 3 · Refuted: 0 · Uncertain: 0


Models: claude-opus-5-5 + gpt-6.1-sol · Trigger: manual · Workflow run

This review runs once per PR. A maintainer can request another with a /ai-review comment.

Comment on lines +18 to +29
import { dbRemoteChanges } from "../commands/db/remote/changes/changes.handler.ts";
import { genKeys } from "../commands/gen/keys/keys.handler.ts";
import { PROJECT_NOT_LINKED_MESSAGE } from "../config/remote-target.service.ts";
import { CliArgs } from "../shared/cli/cli-args.service.ts";
import {
DebugFlag,
DnsResolverFlag,
OutputFlag,
ProfileFlag,
WorkdirFlag,
} from "./global-flags.ts";
import { GoProxy } from "./go-proxy.service.ts";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 MAJOR · merge-resolution · source: claude+codex

The retained integration suite imports three deleted modules, preventing it from loading and breaking the integration test run and typechecking.

Evidence: Lines 18, 19, and 29 import changes.handler.ts, keys.handler.ts, and go-proxy.service.ts; all three files are absent under pr/. apps/cli/vitest.config.ts:89–91 includes this suite through **/*.integration.test.ts. sync-resolution.diff:8375–8403 and :9879–9900 explicitly delete the two handlers.

Suggested fix: Remove the obsolete Go-delegation integration suite.

Comment on lines +25 to +39
export const goProjectTarget = Effect.fn("GoProxy.projectTarget")(function* (
projectRef: Option.Option<string>,
options: { readonly picker?: boolean } = {},
) {
if ((yield* softProjectStateMode) !== "stack") {
const env: Record<string, string> = {};
return { args: Option.isSome(projectRef) ? ["--project-ref", projectRef.value] : [], env };
}
const target = yield* loadTarget(projectRef, options.picker === true).pipe(
Effect.provide(remoteTargetRuntimeLayer),
);
const env: Record<string, string> = {};
if (target.poolerUrl !== undefined) env["SUPABASE_INTERNAL_POOLER_URL"] = target.poolerUrl;
return { args: ["--project-ref", target.ref], env };
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 MINOR · merge-resolution · source: claude

The merge resolutions remove both callers of goProjectTarget but retain its implementation, leaving an unused helper for the removed Go-delegation path.

Evidence: go-proxy-target-env.ts:18–39 documents and implements the Go-delegation helper. Repository-wide searches find no remaining importers or calls. sync-resolution.diff:8375–8403 and :9879–9900 delete handlers that imported and called goProjectTarget.

Suggested fix: Delete go-proxy-target-env.ts alongside the obsolete integration suite.

@@ -0,0 +1 @@
x No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚪ NIT · merge-resolution · source: claude+codex

The merge resolution adds a stray temporary file containing only the character x.

Evidence: The checked-out SIDE_EFFECTS.md.tmp-unused is exactly one byte containing x. sync-resolution.diff:9743–9750 records it as a new file with that content and no trailing newline.

Suggested fix: Delete SIDE_EFFECTS.md.tmp-unused.

@avallete avallete closed this Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do not merge Approve to apply; do not merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants