Skip to content

feat(stack): replace the experimental runtime and integrate CLI commands - #6684

Merged
jgoux merged 67 commits into
developfrom
feat/stack-greenfield-runtime
Sep 21, 2026
Merged

jgoux merged 67 commits into
developfrom
feat/stack-greenfield-runtime

Conversation

@jgoux

@jgoux jgoux commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Replaces the experimental stack supervisor with an Effect-based runtime for native processes and Docker containers. Service recipes, composition, routing, lifecycle ownership, and persistence have explicit boundaries, with stack state and data stored together under ~/.supabase/stacks.

The database starts eagerly while other services start on demand. Stacks support idle/wake, restart, parallel instances, and composition changes that preserve existing service identities and data when --exclude changes.

Integrates the runtime with stack lifecycle commands and dependent database, migration, schema, inspection, type generation, storage, and database testing commands. Database reset preserves identity and ports. Functions serve attaches to the configured service, temporarily includes an excluded service, and restores configuration after temporary overrides.

Keeps the backend behind experimental.stack and documents its supported configuration and limitations. Removes the old stack implementation and updates artifact preparation, bundled PostgreSQL tools, and compiled CLI process dispatch.

@jgoux
jgoux enabled auto-merge September 21, 2026 12:33
@jgoux
jgoux added this pull request to the merge queue Sep 21, 2026
Merged via the queue into develop with commit 171f173 Sep 21, 2026
33 of 35 checks passed
@jgoux
jgoux deleted the feat/stack-greenfield-runtime branch September 21, 2026 12:59
pull Bot pushed a commit to oogalieboogalie/cli that referenced this pull request Sep 21, 2026
After a stack is reopened, its E2E log subscriptions can connect before
the detached owner starts and silently stop, leaving failure reports
with only logs from the previous run. Attach them after the owner starts
and include service health, wake status, and the last error in failure
diagnostics.

Test fixtures only; runtime behavior is unchanged. Follow-up to supabase#6684.
pull Bot pushed a commit to chizee/cli that referenced this pull request Sep 29, 2026
## TL;DR

stops the stack runtime from signalling a reused pid when a container
log stream dies long before its service stops

## what might hurt?

the stack runtime spawned `docker logs --follow` into the service launch
scope
when that follower exited non zero while the container kept running, its
release waited for service stop and then sent `kill(-pid, SIGTERM)` to a
pid that an unrelated process could own by then.

## sorted by:

giving the follower its own scope that closes as soon as it exits, so
the release lands within milliseconds of the exit.

a follower still running at service stop is killed exactly as before,
and the serve tests now also pin the per attempt log scoping from supabase#6594

## ref:

- related: supabase#6858
- missed in: supabase#6684
TFSebben pushed a commit to TFSebben/supabase_cli that referenced this pull request Nov 4, 2026
## TL;DR

fixes image transforms on the stack returning different images than the
legacy backend, by giving the stack's imgproxy the same settings

## what's Improved?

on the stack, `supabase start` ran imgproxy without the tuning the
legacy backend passes it
a png requested by a browser that accepts webp came back as png instead
of webp

animated gifs came back as a single frame, and large photos skipped the
default 3000px size cap

## fixed now by:

the stack's imgproxy now gets the same tuning as the legacy backend, so
transforms return the same images on both
`IMGPROXY_USE_ETAG` is left out because imgproxy treats its legacy value
like unset, so nothing changes there

## ref:

- missed in: supabase#6684
TFSebben pushed a commit to TFSebben/supabase_cli that referenced this pull request Nov 4, 2026
…LI-2577) (supabase#7481)

## TL;DR

fixes functions on the stack getting `[edge_runtime.secrets]` exactly as
written in `config.toml`, so they now see the same secrets as on the
legacy backend

## whats missing?

on the stack, `supabase start` and `supabase functions serve` passed
`[edge_runtime.secrets]` to functions untouched

a secret written as `my_key` stayed lowercase, so
`Deno.env.get("MY_KEY")` came back empty

an `env(NAME)` pointing at an unset variable arrived as the text
`env(NAME)`, and empty secrets arrived as empty strings

## fixed now by:

the stack now runs secrets through the same step the legacy backend
uses, so names are uppercased and empty or unset values are skipped

secrets starting with `SUPABASE_` are skipped too, same as on the legacy
backend

## ref:

- missed in: supabase#6684
kallebysantos pushed a commit to kallebysantos/supabase-cli that referenced this pull request Nov 5, 2026
…77) (supabase#7499)

## TL;DR

fixes the stack's Functions env so `supabase start` and `supabase
functions serve` give functions the same env as the legacy backend

## whats missing?

stack `functions serve` ignored each function's own
`supabase/functions/<slug>/.env`
the stack let `[edge_runtime.secrets]` win over
`supabase/functions/.env`, while legacy lets the file win

on a running stack `--env-file` kept the `functions/.env` values, and
`.env` edits only applied after a restart
multiline values like PEM keys were rejected

`--debug` printed less than legacy and the serve banner showed the
internal port
a stack where only Realtime serves the API failed with `Shared API port
differs from existing claim`

## fixed now by:

legacy and the stack now share one env resolver, and legacy `start` and
`functions serve` output stays exactly the same

stack `functions serve` reads each function's `.env`, re-reads env files
on every run and restores the saved config on exit
multiline values travel in the Functions config on native and docker

Realtime counts as an API source, and the runtime now gets the API port
and debug mode

## ref:

- missed in: supabase#6684
- extends: supabase#7481
TFSebben pushed a commit to TFSebben/supabase_cli that referenced this pull request Nov 11, 2026
…upabase#7571)

## TL;DR

fixes edge functions on the stack connecting to the database as the
`supabase_admin` superuser instead of `postgres`

## whats hurting?

on the stack, `SUPABASE_DB_URL` inside a function pointed at
`supabase_admin`, while the legacy backend and deployed functions get
`postgres`

so a function could run superuser only sql locally that fails once
deployed

tables a function created were also owned by `supabase_admin`, so
migrations and `db query` as `postgres` could not alter them

## now fixed by?

the stack hands functions a `postgres` role url, on `supabase start` and
on `functions serve`
a stack created before this picks it up on its next `stack start`, while
`stack restart` keeps the saved value

## ref:

- missed in: supabase#6684
TFSebben pushed a commit to TFSebben/supabase_cli that referenced this pull request Nov 12, 2026
…#7595)

## TL;DR

fixes the stack replaying `supabase/roles.sql` on a later start and
running it as `supabase_admin`

## what's missing?

adding or dropping a service between starts ran `roles.sql` again, so a
plain `create role` failed with `role "…" already exists`

it also ran as `supabase_admin` instead of `postgres`, so a migration
using a schema from `roles.sql` failed with `permission denied for
schema`

## now fixed by?

the stack runs it once on first setup, as `postgres`, like the legacy
backend

<details><summary>visual rep</summary>

```mermaid
flowchart TD
  A["roles.sql<br/>create role app_user; create schema app"] --> B["first supabase start"]
  B -- before --> C["runs as supabase_admin<br/>app owned by supabase_admin"]
  C -.-> D["migration: create table app.t<br/>permission denied for schema app"]
  B -- now --> E["runs as postgres<br/>app owned by postgres"]
  E --> F["migration: create table app.t<br/>ok"]
  B --> G["stop, then start with another service set"]
  G -- before --> H["roles.sql runs again"]
  H -.-> I["role app_user already exists<br/>start fails"]
  G -- now --> J["roles.sql already applied<br/>start ok"]
  classDef t fill:transparent
  classDef bad fill:transparent,stroke-dasharray:5 4
  class A,B,C,E,F,G,H,J t
  class D,I bad
```

</details>

## ref:

- missed in: supabase#6684
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants