docs(cli): document experimental supabase stack commands and native runtime (#50391)

Add two guides under Local Development for the experimental `supabase
stack` commands, wire them into the docs nav, the CLI reference, the
marketing features list, and the pages that readers reach with a port
conflict.

New pages:
- guides/local-development/parallel-projects: run one local project per
app, git worktree, branch, or named environment on a single machine.
Covers identity, automatic port assignment, removing fixed ports from
config.toml, named projects, finding endpoints, stop and destroy, the
`[experimental] stack` setting, and current limitations.
- guides/local-development/runtimes: the Docker and native runtimes, how
the CLI picks one, native platform requirements, artifact download and
cache locations, and runtime limitations.

Cross-links and context:
- Local development index, CLI getting started, CLI workflows, managing
environments, AI tools, MCP, and the edge functions port troubleshooting
entry now point readers to the new guides where a second `supabase
start` fails on a port conflict.
- CLI reference: `supabase stack`, `stack start`, `stack stop`, `stack
destroy`, the `experimental.stack` config key, and a note on `supabase
start` and `[experimental] stack`.
- www: two feature entries and copy tweaks on the hosted Postgres and
innovation teams solution pages.
- supa-mdx-lint: allow worktree, glibc, musl, and checksum.
This commit is contained in:
Wen Bo Xie authored and GitHub committed 2026-10-02 08:39:18 +02:00
1 parent 6143441493
commit ffd2754c7a
16 files changed
+579 -5

No files matched your search

@@ -2519,6 +2519,14 @@ export const local_development: NavMenuConstant = {
url: undefined,
items: [
{ name: 'Database migrations', url: '/guides/local-development/database-migrations' },
{
name: 'Running multiple local projects',
url: '/guides/local-development/running-multiple-local-projects' as `/${string}`,
},
{
name: 'Docker and native runtimes',
url: '/guides/local-development/docker-and-native-runtimes' as `/${string}`,
},
{
name: 'Declarative database schemas',
url: '/guides/local-development/declarative-database-schemas' as `/${string}`,
+4
View File
@@ -23,4 +23,8 @@ See how these tools perform on real Supabase tasks in [Supabase Evals](/evals),
- **Plugin**: a single install that bundles the MCP server and Agent Skills together for a specific agent.
- **Prompts**: static prompt files you copy into your project for agents that don't support MCP, plugins, or skills natively.
## Local projects for parallel agents
Agents that work in separate git worktrees or branches each need their own database. Otherwise migrations and seed data from one task affect another. With the experimental `supabase stack` commands turned on, `supabase start` gives each worktree or branch its own local Supabase project with its own ports and data. Agents that share one checkout and branch share a local project, so give each agent its own worktree. The commands also run without Docker on Linux and on macOS on Apple silicon, which covers agent sandboxes that have no container engine. See [Running multiple local projects](/docs/guides/local-development/running-multiple-local-projects) and [Docker and native runtimes](/docs/guides/local-development/docker-and-native-runtimes).
<ContentListings id="ai-tools-building-into-app" />
+1 -1
View File
@@ -118,7 +118,7 @@ Parameters can be combined: <code><CustomContent data="mcp:servers">remote</Cust
<Admonition type="note">
When using [Supabase CLI](/docs/guides/local-development) for local development, the MCP server is available at <code><CustomContent data="mcp:servers">local</CustomContent></code>.
When using [Supabase CLI](/docs/guides/local-development) for local development, the MCP server is available at <code><CustomContent data="mcp:servers">local</CustomContent></code>. With the experimental `[experimental] stack` setting on, local projects use assigned ports instead, so read the MCP URL from the output of `supabase status`. See [Running multiple local projects](/docs/guides/local-development/running-multiple-local-projects).
</Admonition>
@@ -22,7 +22,7 @@ height={933}
## Set up a local environment
The first step is to set up your local repository with the Supabase CLI:
The first step is to set up your local repository with the Supabase CLI. Each developer, and each feature branch or git worktree, can have its own local database. To run several local projects at the same time on one machine, see [Running multiple local projects](/docs/guides/local-development/running-multiple-local-projects).
```bash
supabase init
@@ -7,13 +7,15 @@ To develop your applications using the locally running Supabase stack, you'll ne
<Admonition type="note">
A container manager compatible with Docker APIs is a prerequisite:
A container manager compatible with Docker APIs is a prerequisite for `supabase start`:
- [OrbStack](https://orbstack.dev/) (macOS) - recommended on macOS
- [Docker Desktop](https://docs.docker.com/desktop/) (macOS, Windows, Linux) - recommended on Windows and Linux
- [Rancher Desktop](https://rancherdesktop.io/) (macOS, Windows, Linux)
- [Podman](https://podman.io/) (macOS, Windows, Linux)
The experimental `supabase stack` commands can also run a local project as processes on your machine without Docker on Linux and on macOS on Apple silicon. See [Docker and native runtimes](/docs/guides/local-development/docker-and-native-runtimes).
</Admonition>
## Quickstart
@@ -145,6 +147,8 @@ Local development with Supabase allows you to work on your projects in a self-co
Once set up, you can initialize a new Supabase project, start the local stack, and begin developing your application using local Supabase services. This includes access to a local Postgres database, Auth, Storage, and other Supabase features.
With the default ports, `supabase start` runs one local project per machine. To run a local project for each app or git worktree at the same time, use the experimental `supabase stack` commands described in [Running multiple local projects](/docs/guides/local-development/running-multiple-local-projects).
## CLI
The Supabase CLI is a tool that enables developers to run Supabase services locally and manage hosted projects directly from the terminal. It provides a suite of commands for various tasks, including:
@@ -16,6 +16,8 @@ There are two starting points, both leading to the same place: database schema a
You need the Supabase CLI installed and a Docker-compatible runtime running. If you haven't set these up yet, see [Install and run the CLI](/docs/guides/local-development/cli/getting-started) for installation across macOS, Windows, and Linux, and for the details of what `supabase start` brings up and how to access each service.
This guide assumes one running local project. If you work on several apps or git worktrees at once and need a local project for each, see [Running multiple local projects](/docs/guides/local-development/running-multiple-local-projects).
Keep in mind that **the local stack is for development only**. It is not hardened for production use and must never be exposed to external traffic. It has no TLS, no rate limiting, and default credentials. Use it to develop and test, then deploy to the [Supabase Platform](https://supabase.com) or a proper self-hosted setup for anything beyond that.
<Admonition type="note" title="`supabase` vs. `npx supabase`">
@@ -515,3 +517,7 @@ supabase start
```
If problems persist, `supabase stop --no-backup` for a clean restart (this removes local database data).
**`supabase start` fails because a port is already allocated**
Another local Supabase project is using the default ports. Stop it with `supabase stop` from its directory. To run both projects at the same time, turn on the experimental `supabase stack` commands and remove the fixed ports from each project's `config.toml`. See [Running multiple local projects](/docs/guides/local-development/running-multiple-local-projects).
@@ -405,6 +405,8 @@ When you are finished working on your Supabase project, you can stop the stack (
supabase stop
```
With the default ports, `supabase start` runs one local project per machine, because every project's `config.toml` uses the same ports. To run several local projects or git worktrees at the same time, see [Running multiple local projects](/docs/guides/local-development/running-multiple-local-projects).
## Telemetry
The Supabase CLI collects telemetry data about general usage. Participating in this program is optional, and you can opt out at any time.
@@ -0,0 +1,112 @@
---
id: 'docker-and-native-runtimes'
title: 'Docker and native runtimes'
description: 'How the experimental supabase stack commands run a local Supabase project in Docker or as native processes, how the CLI picks a runtime, and what the native runtime needs.'
subtitle: 'Run a local Supabase project in containers or as processes on your machine without Docker'
---
This guide explains the two runtimes the experimental `supabase stack` commands use, how the CLI picks one, and which to choose. The Docker runtime runs each service in a container, with Docker or Podman. The native runtime runs each service as a process on your machine, with no container engine, on Linux and on macOS on Apple silicon.
Both runtimes run the same local Supabase project with the same services. The default `supabase start` command always uses Docker. The runtime choice exists only after you turn on the `[experimental] stack` setting. See [Running multiple local projects](/docs/guides/local-development/running-multiple-local-projects#turn-on-the-stack-commands) for how to turn it on.
<Admonition type="caution" title="Experimental">
The `supabase stack` commands are experimental. Their flags and output can change between releases, and the CLI compatibility promise doesn't cover them.
</Admonition>
## Which runtime to choose
Use Docker when Docker or Podman is available. Containers give each local project its own network namespace and file system. That isolation matters most when you run several local projects on one machine.
Use the native runtime where no container engine is available, such as coding agent sandboxes and CI runners. The native runtime is intended for one local project per environment. Native processes share the host's process table and file locks. Several native local projects on one machine are less isolated from each other than containers are.
## How the two runtimes differ
The following table compares how each runtime runs services, what it needs, and where it stores data.
| | Docker runtime | Native runtime |
| -------------------------------- | --------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| Flag | `--runtime docker` or `--runtime podman` | `--runtime native` |
| How services run | One container per service, from images the CLI pulls | One process per service, from archives the CLI downloads and verifies |
| Requires | A running Docker or Podman engine | A supported platform, `tar` on the host, and, on first start, network access to the archive download hosts |
| Database data | A Docker volume when the Docker client and daemon are both version 26 or later, or a host directory otherwise | `~/.supabase/stacks/<id>/` in your home directory |
| Downloaded artifacts | The engine's image cache | `~/.supabase/cache/stack` in your home directory, shared by all local projects |
| Isolation between local projects | Separate network namespaces and file systems | Shared host process table and file locks |
Both runtimes keep each local project's saved settings under `~/.supabase/stacks/<id>/`. The native runtime keeps its database data there too. If you set `SUPABASE_HOME`, the CLI uses that directory instead of `~/.supabase`.
In both runtimes, Postgres starts right away and other services start on their first request. By default, services that started this way stop again after 60 seconds idle, and Studio after 5 minutes. Functions doesn't stop on its own. A service also stays up while a running service depends on it, such as pgmeta while Studio runs. Pass `--eager` to start every enabled service before the command returns and turn off idle stops.
Starting a service on demand doesn't mean downloading it on demand. By default, the first `supabase start` pulls or downloads every enabled service before it returns. Pass `--preparation on-demand` to defer each download until the service's first request.
## How the CLI picks a runtime
When you don't pass `--runtime`, a new local project uses the first of these that responds:
1. Docker, when the Docker daemon answers `docker version`
2. Podman, when the Podman engine answers `podman info`
3. Native, on Linux `amd64` and `arm64` and on macOS on Apple silicon
Each check waits up to 10 seconds. Having the `docker` command installed isn't enough. If the Docker daemon is stopped, the CLI moves on to Podman or native. It prints a notice that it skipped Docker, with the steps to switch. With no responding engine on a platform without native support, the start fails and asks you to start Docker or Podman.
Passing `--runtime docker`, `--runtime podman`, or `--runtime native` requires that runtime, and the CLI never falls back to another one. If Docker isn't reachable with `--runtime docker`, the start fails and suggests starting Docker, or `--runtime native` for a new local project on a supported platform. With `--runtime native` on an unsupported platform, the start fails before the CLI creates the local project.
The CLI records the runtime when it creates a local project and reuses it on every later start, without checking again. Passing a different `--runtime` to a local project that you already created fails. To move an app to another runtime, start a new named local project, or destroy the local project and start it again. The CLI doesn't convert data between runtimes.
Different apps on one machine can use different runtimes.
## Native runtime requirements
The native runtime runs on these platforms:
| Platform | Support |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Linux on `amd64` or `arm64` | Supported on Ubuntu 22.04 or later, or another distribution with glibc 2.35 or later. Some services use the host's glibc. |
| macOS on Apple silicon | Supported on macOS 14 or later. |
| Windows | Not supported. Use Docker. |
| macOS on Intel | Not supported. Use Docker. |
The native runtime doesn't run as `root`, because Postgres `initdb` can't. To run it as `root`, such as in a CI container, set `SUPABASE_NATIVE_POSTGRES_USER` to a non-root account. Create the account first if it doesn't exist. The CLI then runs Postgres as that user. In some supported coding agent sandboxes, the CLI finds a suitable non-root account without the variable.
On first start, the CLI downloads service archives from the [`supabase/slim-services` GitHub releases](https://github.com/supabase/slim-services/releases), with `supabase-cli-artifacts.s3.us-east-1.amazonaws.com` as a fallback. It verifies their checksums and extracts them with the system `tar`, so install `tar` in minimal sandbox images. In a sandbox with an allowlist, allow `github.com` or that S3 host. Allowing only `ghcr.io` isn't enough.
To download the archives ahead of time without starting any services, such as when you build a sandbox image, run:
```bash
supabase stack prepare --runtime native
```
If the local project doesn't exist, `prepare` creates it, so it appears in `supabase stack list` and you can remove it with `supabase stack destroy`.
The cache in `~/.supabase/cache/stack` is shared by every local project on the machine, and `supabase stack destroy` leaves it in place. Delete that directory to reclaim its disk space and force a fresh download.
## Start with a specific runtime
Start a local project in the native runtime:
```bash
supabase start --runtime native
```
Require Docker for a new local project:
```bash
supabase start --runtime docker
```
Check which runtime a local project uses:
```bash
supabase stack status --output-format json
```
The `runtime` field is `docker`, `podman`, or `native`. The text output of `supabase status` and `supabase stack list` shows the runtime too.
## Limitations
- A local project keeps the runtime it was created with, and the CLI doesn't move data between runtimes. See [How the CLI picks a runtime](#how-the-cli-picks-a-runtime).
- Running several native local projects on one machine works, but they share host resources without the isolation containers provide. Use Docker for that case.
- If Postgres takes too long to become ready on a cold start, raise `health_timeout` under `[db]` in `config.toml`. Both runtimes use that setting.
<ContentListings id="local-development-runtimes-learn-more" />
@@ -0,0 +1,283 @@
---
id: 'running-multiple-local-projects'
title: 'Running multiple local projects'
description: 'Run more than one local Supabase project on the same machine, one per app, git worktree, or named environment, with the experimental supabase stack commands.'
subtitle: 'Run a local Supabase project for every app, git worktree, or environment on one machine'
---
This guide explains how to run more than one local Supabase project on one machine with the experimental `supabase stack` commands. Use it when you switch between apps, work in several git worktrees, run coding agents in parallel, or want separate `dev` and `test` environments for one app.
In this guide, a local project is the set of Supabase services running on your machine for one app, the same thing `supabase start` gives you. Your app is your own code, in the directory where you ran `supabase init`.
With the default ports, `supabase start` runs one local project per machine. Every app's generated `config.toml` uses the same ports, so a second local project fails with a port conflict. The `supabase stack` commands assign each local project its own ports and keep its data separate.
This guide covers:
- [How local projects stay isolated](#how-local-projects-stay-isolated) explains which directories, branches, and names get their own local project. Read it first if you use a monorepo or run several agents.
- [Turn on the stack commands](#turn-on-the-stack-commands) and [Remove fixed ports from config.toml](#remove-fixed-ports-from-configtoml) are one-time setup for each app.
- [Start a local project in each app directory or worktree](#start-a-local-project-in-each-app-directory-or-worktree) through [Stop and destroy local projects](#stop-and-destroy-local-projects) cover day-to-day use.
- [Differences from the default `supabase start`](#differences-from-the-default-supabase-start) and [Limitations](#limitations) list what changes when you switch.
<Admonition type="caution" title="Experimental">
The `supabase stack` commands are experimental. Their flags and output can change between releases, and the CLI compatibility promise doesn't cover them. Local projects started with these commands keep their own data, separate from any local project started with the default `supabase start`.
</Admonition>
## How local projects stay isolated
Every local project has an identity made from three parts:
- **Project root**: the nearest directory, starting from your current directory and walking up, that contains `supabase/config.toml`. Without a config file, the project root is the current directory.
- **Git branch**: if the project root is in a git repository, the current branch is part of the identity. The CLI reads it from the `.git` metadata, so git doesn't need to be installed.
- **Name**: an optional name that you pass with `--stack`.
Two local projects with different identities never share containers, processes, ports, database data, or Storage data. You get a separate local project for each:
- App with its own `supabase/` directory
- Git worktree, because each worktree is a different directory
- Git branch, when you check out a different branch in the same directory
- Name you pass with `--stack`, so one app can run `dev` and `test` side by side
Everything else shares one local project. Packages in a monorepo get separate local projects only if each one has its own `supabase/` directory. Two packages under one `supabase/` directory share a local project. So do two coding agents working in the same checkout on the same branch. To isolate them, use separate git worktrees or different `--stack` names.
Local projects for the same project root also share the project files in its `supabase/` directory. For example, Studio saves SQL snippets to `supabase/snippets`, so the `dev` and `test` local projects of one app see the same snippets.
The CLI assigns ports for each local project from the range 20000 to 32767 and keeps them stable across restarts. Ports written in `config.toml` are used as written, so see [Remove fixed ports from config.toml](#remove-fixed-ports-from-configtoml) first.
## Before you begin
You need:
- Supabase CLI v2.119.0 or later. See [Install and run the CLI](/docs/guides/local-development/cli/getting-started).
- A container engine or a supported platform. The Docker runtime needs a running Docker or Podman engine, and is the recommended runtime for several local projects at the same time. The native runtime needs no container engine but runs only on macOS on Apple silicon and on Linux for `amd64` and `arm64`. See [Choose a runtime](#choose-a-runtime).
- An app directory initialized with `supabase init`, or a directory without a `supabase/config.toml`. Without a config file, the local project starts with default settings and doesn't create a config file.
## Turn on the stack commands
The `supabase stack` commands exist only when the `[experimental] stack` setting is on. Without it, `supabase stack` commands fail with `Unknown subcommand "stack"`.
1. Add this to `supabase/config.toml` in your app directory:
```toml
[experimental]
stack = true
```
In a directory without a `config.toml`, set the environment variable instead:
```bash
export SUPABASE_EXPERIMENTAL_STACK=1
```
2. Confirm that the commands are available:
```bash
supabase stack --help
```
The help starts with `Manage an experimental, unstable local Supabase stack`. If you see the general `Supabase CLI` help instead, the setting isn't on.
With the setting on, `supabase start`, `supabase status`, and `supabase stop` run the stack commands. The rest of this guide uses those top-level commands. `supabase stack start`, `supabase stack status`, and `supabase stack stop` do the same thing. Commands that only exist under `supabase stack`, such as `list` and `destroy`, keep the prefix.
The setting also routes the local targets of the `db`, `migration`, `test`, `gen`, `inspect`, `pull`, `storage`, `seed`, and `services` commands, and `functions serve`, to the stack.
The environment variable takes precedence over the config file. Set `SUPABASE_EXPERIMENTAL_STACK=0` to use the default commands for one session without editing the file.
## Remove fixed ports from config.toml
`supabase init` writes fixed ports into `config.toml`. The CLI treats a port in the file as an exact request. Two local projects that both request port `54321` can't run at the same time.
For a new app, run `init` with the setting turned on. The CLI writes `[experimental] stack = true` and leaves the port keys out:
```bash
SUPABASE_EXPERIMENTAL_STACK=1 supabase init
```
For an app that already has a `config.toml`, remove the port lines from each app that you want to run in parallel:
1. Open `supabase/config.toml` in your app directory.
2. Delete or comment out these keys:
- `port` under `[api]`, `[db]`, `[db.pooler]`, `[studio]`, `[local_smtp]`, and `[analytics]`
- `shadow_port` under `[db]`
- `inspector_port` under `[edge_runtime]`
- `smtp_port` and `pop3_port` under `[local_smtp]`, and `vector_port` under `[analytics]`, if you set them. `supabase init` writes the SMTP ports commented out.
3. Save the file and commit it, so everyone on the team gets the same behavior.
Remove the ports before the app's first `supabase start` with the setting on. A local project keeps the ports it was created with. If you already started one with the fixed ports, removing them afterward makes `supabase start` fail with `cannot change on the saved stack`. Start a new local project with a different `--stack` name, or run `supabase stack destroy` and start again. Destroying deletes the local project's data.
The CLI also treats ports you set with an environment variable, such as `SUPABASE_API_PORT` or `SUPABASE_DB_PORT`, as exact requests. If another process already listens on that port, the start fails. When the port belongs to another local project, the error names that local project.
## Start a local project in each app directory or worktree
The following steps start two independent local projects from two app directories. The same steps work for git worktrees of one repository.
1. Open a terminal in the first app directory and start its local project:
```bash
supabase start
```
When the local project is ready, the command prints `Stack is ready.` and a connection summary. The summary lists the API, REST, Functions, Studio, MCP, Mailpit, and database URLs, the publishable and secret keys, the state of each service, and the runtime.
2. Open a second terminal in the other app directory or worktree and run the same command:
```bash
supabase start
```
The second local project gets its own ports and its own database. Both keep running after the commands return.
3. Point each app at the Project URL of its own local project. The ports stay the same the next time you start it. To write the URLs and keys to a dotenv file, see [Find a local project's endpoints and keys](#find-a-local-projects-endpoints-and-keys).
The first start in each runtime takes longer. By default, the command downloads or pulls every enabled service before it returns. Later starts reuse the cache. To defer each download until the service's first request, pass `--preparation on-demand`.
Postgres starts right away. Other services start on their first request. By default, they stop again after 60 seconds idle, and Studio after 5 minutes. Functions doesn't stop on its own. A service also stays up while a running service depends on it, such as pgmeta while Studio runs. To start every enabled service before the command returns and turn off idle stops, pass `--eager`.
To leave services out, pass `--exclude` with one or more of `rest`, `auth`, `realtime`, `storage`, `functions`, `studio`, `mail`, `analytics`, and `pooler`:
```bash
supabase start --exclude studio,mail
```
The database can't be excluded. Studio needs the REST API, so to exclude `rest`, exclude `studio` too. Excluding `studio` also removes the MCP server, because Studio serves `/mcp`.
Running `supabase start` again on a running local project keeps its current settings and prints `Stack is already running with its current services`. To apply a change to `config.toml`, `--exclude`, or `--eager`, stop the local project and start it again. Starting without `--exclude` restores the services enabled in `config.toml`.
Stopping and starting doesn't apply changes to ports or to the Postgres major version. For those, start a new local project with a different `--stack` name, or run `supabase stack destroy` and start again.
## Run named local projects for one app
One app can run several local projects by name. This keeps a destructive test run away from your development data.
1. Start a `dev` local project:
```bash
supabase start --stack dev
```
2. Start a `test` local project in the same directory:
```bash
supabase start --stack test
```
3. Pass the same `--stack` name to `supabase status`, `supabase stop`, and `supabase stack destroy` to target that local project later.
A local project started without `--stack` is the app directory's default local project. Named local projects and the default one are independent of each other.
The `db`, `migration`, and other database commands use the default local project for the current branch. They can't target a named local project. See [Limitations](#limitations).
## Find a local project's endpoints and keys
Ports differ between local projects, so don't assume the defaults from the CLI documentation. To see the URLs, keys, and service states of a local project, run this in its app directory:
```bash
supabase status
```
Pass `--stack <name>` for a named local project. The local database password is `postgres`, so the database URL in the output works with `psql` and `--db-url`.
To export the connection details as environment variables, pass `--env`:
```bash
supabase status --env --output-format text > .env.local
```
The file includes `API_URL`, `DB_URL`, `PUBLISHABLE_KEY`, `SECRET_KEY`, `ANON_KEY`, and `SERVICE_ROLE_KEY`, plus the URLs of the other available services. To match the variable names your framework expects, pass `--override-name`:
```bash
supabase status --env --override-name API_URL=NEXT_PUBLIC_SUPABASE_URL,ANON_KEY=NEXT_PUBLIC_SUPABASE_ANON_KEY
```
For scripts and agents, request JSON from `supabase start` or `supabase status`:
```bash
supabase start --output-format json
```
The `start` JSON includes the local project's `id`, its `runtime`, `lazy_services` that start on their first request, and the same `env` map that `--env` exports. Its `endpoints` object is keyed by service and endpoint, such as `database.sql`, and each entry has a `protocol`, `address`, `port`, and `url`.
To list every local project on the machine, across all apps, run:
```bash
supabase stack list
```
The list shows each local project's name, project root, branch, runtime, and a short ID. Pass `--output-format json` to get the full ID that `--stack-id` accepts.
To stream live logs from a local project, run `supabase stack logs`. Pass `--service database` to limit the output to one service.
## Choose a runtime
A local project runs in the Docker runtime or the native runtime. The Docker runtime runs each service in a container, with Docker or Podman. The native runtime runs each service as a process on your machine, with no container engine. It runs on macOS on Apple silicon and on Linux `amd64` and `arm64`. Both runtimes run the same services.
For several local projects on one machine, use Docker. Containers give each local project its own network namespace and file system. Native local projects share the host's process table and file locks. Use the native runtime where no container engine is available, such as coding agent sandboxes and CI runners.
When you don't pass `--runtime`, a new local project uses Docker if the Docker daemon responds, then Podman, then native on supported platforms. Having the `docker` command installed isn't enough. The runtime is fixed for the life of a local project. For details, platform requirements, and what the native runtime downloads, see [Docker and native runtimes](/docs/guides/local-development/docker-and-native-runtimes).
## Stop and destroy local projects
Stopping a local project keeps its data and ports. Destroying it deletes its data.
To stop the app directory's default local project, run this in that directory:
```bash
supabase stop
```
To stop a named local project, pass its name:
```bash
supabase stop --stack test
```
To stop every local project on the machine, across all apps, pass `--all`. If any local project fails to stop, the command exits with an error that lists the failed local projects:
```bash
supabase stack stop --all
```
To permanently delete one local project and its data, run `supabase stack destroy`. The command asks for confirmation. Pass `--yes` to skip the prompt in scripts:
```bash
supabase stack destroy --stack test --yes
```
<Admonition type="danger">
`supabase stack destroy` deletes the local project's database data and frees its ports. There is no backup and no undo. There is also no bulk destroy, so one command removes one local project.
</Admonition>
`destroy` keeps two kinds of data:
- Storage upload files, which live in your app at `supabase/.temp/stack-uploads/<id>/`. Delete that directory to remove them.
- Container engine resources, if Docker or Podman isn't running. If no process for the local project is still running, the command removes the local project's registration. It prints cleanup commands to run after the engine starts again. Otherwise it fails and asks you to start the engine and retry.
The printed cleanup command deletes only this local project's database data, from a Docker volume that other local projects share. Don't delete the volume itself.
## Differences from the default `supabase start`
Keep these differences in mind when you turn the setting on for an app that used the default `supabase start`:
- Local projects started this way keep separate data. Turning on the setting doesn't copy the database from a local project you started with the default `supabase start`. It also doesn't stop that local project.
- `supabase stop --no-backup` and `supabase stop --project-id` aren't available. Use `supabase stack destroy` to remove data and `supabase stack stop --all` to stop every local project.
- The `-o` and `--output` flags aren't available. Use `--output-format` instead, and `--env` in place of `-o env`.
- `functions serve` needs a running local project. Start one with `supabase start` first.
## Limitations
- Some `config.toml` settings aren't supported. `supabase start` fails with a message that names the setting. The unsupported settings are:
- `api.tls`
- The Analytics GCP settings, and Analytics backends other than Postgres
- Custom Auth email templates with `content_path`
- Storage Analytics and Storage vector buckets
- A custom `edge_runtime.deno_version`
- OrioleDB, and `db.major_version` values other than 15 and 17
- Database commands can't target a named local project. `supabase db reset`, `supabase db diff`, `supabase db pull`, `supabase db dump`, and the other local database commands use the app directory's default local project for the current branch, and don't accept `--stack`.
- Switching branches switches local projects. The git branch is part of the identity. After you check out another branch in the same directory, `supabase start` creates or resumes a different local project with its own data. The first branch's local project keeps running until you stop it.
- Moving or renaming an app directory creates a new local project, because the identity includes the project root path. The previous local project's data stays until you destroy it.
- `supabase stack logs` streams new log lines only. It has no history.
<ContentListings id="local-development-parallel-projects-learn-more" />
@@ -44,6 +44,8 @@ Another process may be using the required ports. Check for:
- Docker containers
- Other development servers
If the conflict comes from another Supabase project, run both projects at the same time with the experimental `supabase stack` commands. They assign each local project its own ports. Turn on the commands and remove the fixed ports from each project's `config.toml` first. See [Running multiple local projects](/docs/guides/local-development/running-multiple-local-projects).
### Deno cache issues
Clear the Deno cache if you're experiencing module resolution problems:
+6
View File
@@ -18,6 +18,10 @@ import {
gettingStartedUseCases,
gettingStartedWebAppDemos,
} from './getting-started.data'
import {
localDevelopmentParallelProjectsLearnMore,
localDevelopmentRuntimesLearnMore,
} from './local-development.data'
import { logDrainsDestinations } from './log-drains.data'
import { realtimeExamples, realtimeGetStarted, realtimeResources } from './realtime.data'
import { resourcesMigrate, resourcesOverview, resourcesPostgres } from './resources.data'
@@ -55,6 +59,8 @@ const ALL_GROUPS: readonly ContentListingGroup[] = [
gettingStartedFrameworkQuickstarts,
gettingStartedWebAppDemos,
gettingStartedMobileTutorials,
localDevelopmentParallelProjectsLearnMore,
localDevelopmentRuntimesLearnMore,
logDrainsDestinations,
realtimeGetStarted,
realtimeExamples,
@@ -0,0 +1,62 @@
import type { ContentListingGroup } from '~/lib/content-listings.schema'
export const localDevelopmentParallelProjectsLearnMore: ContentListingGroup = {
id: 'local-development-parallel-projects-learn-more',
heading: 'Learn more',
type: 'grid',
columns: 2,
items: [
{
title: 'Install and run the CLI',
href: '/guides/local-development/cli/getting-started',
description: 'Install the CLI and start your first local project.',
},
{
title: 'Local development workflow',
href: '/guides/local-development/cli-workflows',
description: 'Day-to-day commands for one local project, from migrations to troubleshooting.',
},
{
title: 'Docker and native runtimes',
href: '/guides/local-development/docker-and-native-runtimes',
description:
'How the CLI picks a runtime, what the native runtime needs, and where it stores data.',
},
{
title: 'Managing config and secrets',
href: '/guides/local-development/managing-config',
description:
'Keep configuration and secrets consistent across local, staging, and production.',
},
{
title: 'CLI configuration',
href: '/guides/local-development/cli/config',
description: 'Every key in config.toml, including the experimental stack setting.',
},
],
}
export const localDevelopmentRuntimesLearnMore: ContentListingGroup = {
id: 'local-development-runtimes-learn-more',
heading: 'Learn more',
type: 'grid',
columns: 3,
items: [
{
title: 'Running multiple local projects',
href: '/guides/local-development/running-multiple-local-projects',
description:
'Run a local project for every app, git worktree, or environment on one machine.',
},
{
title: 'Install and run the CLI',
href: '/guides/local-development/cli/getting-started',
description: 'Install the CLI and start your first local project.',
},
{
title: 'CLI configuration',
href: '/guides/local-development/cli/config',
description: 'Every key in config.toml, including the experimental stack setting.',
},
],
}
+15
View File
@@ -63,6 +63,8 @@ parameters:
description: |
A string used to distinguish different Supabase projects on the same host. Defaults to the working directory name when running `supabase init`.
Local projects started with the experimental `supabase stack` commands are identified by their project directory, git branch, and `--stack` name instead. See [Running multiple local projects](https://supabase.com/docs/guides/local-development/running-multiple-local-projects).
- id: 'api.enabled'
title: 'api.enabled'
tags: ['api']
@@ -1758,6 +1760,19 @@ parameters:
- name: Self-hosted Logflare Configuration
link: https://supabase.com/docs/reference/self-hosting-analytics/list-endpoints#getting-started
- id: 'experimental.stack'
title: 'experimental.stack'
tags: ['experimental']
required: false
default: 'false'
description: |
Turns on the experimental `supabase stack` commands, and makes the top-level `supabase start`, `supabase status`, and `supabase stop` commands run `supabase stack start`, `supabase stack status`, and `supabase stack stop`. The local targets of the `db`, `migration`, `test`, `gen`, `inspect`, `pull`, `storage`, `seed`, and `services` commands, and `functions serve`, also use the stack. With this setting, several local projects can run at the same time on one machine. On supported platforms a local project can also run without Docker.
Local projects started this way keep their own data, separate from local projects started with the default `supabase start`. The environment variable `SUPABASE_EXPERIMENTAL_STACK=1` or `0` overrides this value.
Note: This is an experimental feature and may change in future releases.
links:
- name: 'Running multiple local projects'
link: 'https://supabase.com/docs/guides/local-development/running-multiple-local-projects'
- id: 'experimental.webhooks.enabled'
title: 'experimental.webhooks.enabled'
tags: ['experimental']
+63
View File
@@ -2132,6 +2132,7 @@ Supabase's Command Line Interface (CLI) tool provides developers with a powerful
5. Environment management: Handle multiple environments (development, staging, production) efficiently.
6. Seed data management: Populate your database with test data for consistent development and testing.
7. CI/CD integration: Incorporate Supabase operations into your continuous integration and deployment pipelines.
8. Parallel local projects: Run a separate local project for each app, git worktree, or named environment with the experimental \`supabase stack\` commands.
## The CLI is particularly valuable for:
- Development teams working on Supabase projects collaboratively
@@ -2154,6 +2155,68 @@ By leveraging the Supabase CLI, you can significantly improve your development w
availableOnSelfHosted: true,
},
},
{
title: 'Parallel local projects',
subtitle: 'Run a local Supabase project for every app or git worktree.',
description: `
The Supabase CLI can run more than one local Supabase project on the same machine. Each local project belongs to its project directory and git branch. Every app or git worktree gets its own Postgres database, Auth, Storage, and other services, with separate ports and data.
With the default ports, a second \`supabase start\` on the same machine fails with a port conflict. The experimental \`supabase stack\` commands assign ports automatically and keep them stable across restarts. One app can also run several named local projects, such as \`dev\` and \`test\`, so a destructive test run never touches your development data.
## Key benefits
1. One local project per worktree: Run coding agents in separate git worktrees, each against its own database.
2. Automatic ports: The CLI assigns ports from a shared range and keeps them across restarts. Remove the fixed ports from \`config.toml\` once, or create the project with the stack commands turned on.
3. Named environments: Start \`--stack dev\` and \`--stack test\` side by side in one app.
4. Docker or native runtime: Run in containers, or as processes on your machine without Docker on Linux and on macOS on Apple silicon. Use Docker when you run several local projects on one machine.
5. Services start on demand: Postgres starts right away. Other services start on their first request and stop when idle, which keeps idle local projects light.
## Parallel local projects are valuable for:
- Developers running coding agents in git worktrees
- Teams that keep separate development and test databases on one machine
- Freelancers and consultants switching between several client apps
- CI jobs and agent sandboxes that run without a Docker daemon
The \`supabase stack\` commands are experimental. Their interface can change between releases. See the documentation for the full workflow and limitations.
`,
icon: Terminal,
products: [ADDITIONAL_PRODUCTS.PLATFORM],
heroImage: '',
docsUrl: 'https://supabase.com/docs/guides/local-development/running-multiple-local-projects',
slug: 'parallel-local-projects',
status: {
stage: PRODUCT_STAGES.PUBLIC_ALPHA,
availableOnSelfHosted: true,
},
},
{
title: 'Native runtime for local development',
subtitle: 'Run a local Supabase project as processes on your machine, without Docker.',
description: `
The Supabase CLI can run a local Supabase project as native processes instead of containers. Coding agent sandboxes and CI runners often have no Docker daemon. There, \`supabase stack start\` downloads verified service binaries and runs Postgres, Auth, Storage, and the other services directly on the host.
It is the same local project you get from \`supabase start\`, with the same services and most of the same \`config.toml\` settings. The CLI picks Docker when its daemon responds, then Podman, then native. To require one, pass \`--runtime docker\`, \`--runtime podman\`, or \`--runtime native\`.
## Key benefits
1. Works without Docker: Bring up a real local Supabase project in environments that can't run a container engine.
2. Verified binaries: The CLI downloads service archives from Supabase's GitHub releases and checks them before extracting.
3. Same project, same services: Postgres with the full extension set, Auth, PostgREST, Realtime, Storage, Edge Functions, Studio, and more.
## The native runtime is valuable for:
- Coding agents running in sandboxes with no container engine
- CI jobs on runners without a Docker daemon
The native runtime supports Linux on amd64 and arm64 and macOS on Apple silicon. Windows and Intel Macs use Docker. For several local projects on one machine, Docker remains the recommended runtime. The \`supabase stack\` commands are experimental.
`,
icon: Terminal,
products: [ADDITIONAL_PRODUCTS.PLATFORM],
heroImage: '',
docsUrl: 'https://supabase.com/docs/guides/local-development/docker-and-native-runtimes',
slug: 'native-local-runtime',
status: {
stage: PRODUCT_STAGES.PUBLIC_ALPHA,
availableOnSelfHosted: true,
},
},
{
title: 'Management API',
subtitle: 'Manage your projects programmatically.',
+8 -1
View File
@@ -272,7 +272,14 @@ const data: () => {
description: (
<>
Version-control your schema and run the full stack locally with{' '}
<code className="text-xs">supabase start</code>.
<code className="text-xs">supabase start</code>. With the experimental{' '}
<a
href="/docs/guides/local-development/running-multiple-local-projects#turn-on-the-stack-commands"
className="hover:text-foreground underline"
>
stack setting
</a>
, run one local project per app and worktree.
</>
),
icon: SquareTerminal,
+1 -1
View File
@@ -204,7 +204,7 @@ const data: () => {
},
{
name: 'Claude & Cursor',
description: 'AI-powered local development',
description: 'AI-powered local development, one local project per git worktree',
},
{
name: 'Figma',