# Local development
Source: https://sovaria.in/docs/local-development

Run the whole Sovaria stack on your machine with sov start: auth, SQL, storage, logs and mail, plus functions, realtime and a local console — with well-known keys, your migrations and seed data, and a .env.local for your app.

`sov start` runs the same services your cloud project uses, as Docker containers on your machine. It creates a developer account, an organization and a project, applies `sovaria/migrations`, loads `sovaria/seed.sql`, and writes the project URL and keys into `.env.local`. Nothing leaves your machine except the image download; every email lands in a local inbox.

(Diagram: What sov start runs — Every port is published on 127.0.0.1. The gateway refuses to start if it is published anywhere else.)

## Start the stack

1. **Install Docker** — Docker Desktop, or Docker Engine with the Compose v2 plugin. You don't need a Sovaria account for the local stack.
2. **Start it in your project folder** — The first start downloads the images (pinned to your CLI version) and takes a few minutes; later starts take seconds.
```bash
cd my-app
sov start                          # core services
sov start --with forge,pulse,console   # plus functions, realtime and the local console
```
3. **Use the URL and keys** — `sov status` prints them; `.env.local` already has them for your framework (`SOVARIA_URL`, `VITE_SOVARIA_URL`, `NEXT_PUBLIC_SOVARIA_URL` and the anon key).
```bash
sov status
```

| Service | Address |
|---|---|
| API (gateway) | `http://localhost:54321` — or `http://<ref>.localhost:54321` |
| Postgres | `postgresql://postgres:postgres@127.0.0.1:54322/sovaria_free` (your project is one schema in it; `SOVARIA_DB_URL` in `.env.local` selects it) |
| Local console | `http://localhost:54323` (with `--with console`) |
| Mail inbox (Mailpit) | `http://localhost:54324` — sign-up confirmations, password resets, magic links |

## Well-known local keys

The local stack always uses the same two keys, so tests and example code can hard-code them. They are **public** and they only work against a local stack: the cloud refuses them, and the local gateway answers only requests addressed to `localhost`.

| Key | Value | Use it |
|---|---|---|
| Anon (publishable) | `svr_local_anon_5a0f1c8e2b7d4e6f9a3c1b5d7e9f0a2c` | In your app, like the anon key of a cloud project |
| Service role | `svr_local_service_8d3b6f1a9c2e4d7b0f5a3c8e1d6b9f2a` | Server code and tests only (bypasses row-level security) |
| Developer account | `dev@sovaria.local` / `sovaria-local-dev` | Sign in to the local console |

> **Warning:** Never publish the local stack's ports beyond 127.0.0.1. `sov start` refuses `SOVARIA_LOCAL_BIND` values other than loopback, and the gateway stops at start-up when it would be reachable from your network.

## Point your app at the local stack

JavaScript:
```ts
import { createClient } from '@sovaria/sdk'

const sov = createClient(import.meta.env.VITE_SOVARIA_URL, import.meta.env.VITE_SOVARIA_ANON_KEY)
// local: http://localhost:54321 + svr_local_anon_…   cloud: https://<ref>.sovarias.in + your anon key
```

Python:
```python
from sovaria import SovariaClient

# Reads SOVARIA_URL and SOVARIA_PUBLISHABLE_KEY (load .env.local first, e.g. with python-dotenv)
async with SovariaClient.from_env() as sov:
    print(await sov.get_engines_health())
```

Flutter / Android emulator:
```dart
// The Android emulator reaches your machine as 10.0.2.2; iOS simulators use localhost.
final sovaria = await Sovaria.initialize(url: 'http://10.0.2.2:54321', anonKey: 'svr_local_anon_5a0f1c8e2b7d4e6f9a3c1b5d7e9f0a2c');
```

> **Note:** Plain `http://localhost:54321` means your local project; `http://<ref>.localhost:54321` names it explicitly (browsers resolve `*.localhost` on their own). The same code runs against the cloud when only the two environment variables change.

## Use the CLI against it

`sov start` saves a CLI profile called `local` with a signed-in developer session. Add `--profile local` to any command; `sov simulate local` uses it by default and `sov fn serve` reads `.env.local`, so functions you run locally call the local stack.

Terminal:
```bash
sov db sql --profile local "select count(*) from todos"
sov db migrations new add_notes && sov db migrations push --profile local
sov db reset --local               # drop every table, re-apply migrations and seed
sov fn serve functions/            # SOVARIA_URL and keys come from .env.local
sov simulate local                 # full access simulation against the local stack
```

## Data: keep, reset or start from production's shape

- `sov stop` stops the containers and keeps the database, files and logs; `sov stop --reset` deletes them.
- `sov db reset --local` empties only the database, then applies your migrations and seed again.
- `sov start --from-snapshot snapshot.json` recreates the tables, row-level security, policies, SQL functions and sample rows of a cloud project from a [simulation snapshot](https://sovaria.in/docs/offline-simulation) (`sov simulate snapshot --rows`). No credentials or app users are copied.

## How the local stack differs from the cloud

|  | Local stack | Cloud project |
|---|---|---|
| Plan limits | None: every local organization is on Enterprise | Your plan |
| Database | One Postgres, one schema per project | A dedicated Postgres per project |
| Email | Captured by Mailpit | Sent |
| Files | On a Docker volume | Object storage |
| Keys | Well-known, local only | Generated per project |
| Backups, point-in-time recovery, replicas | Not available | By plan |

## Settings

| Variable | Default | What it does |
|---|---|---|
| `SOVARIA_LOCAL_IMAGE_NAMESPACE` (or `--image-namespace`) | `sovaria` | Registry namespace of the `sovaria-local-*` images, e.g. a mirror in your company registry |
| `SOVARIA_LOCAL_IMAGE_TAG` | the CLI version | Image version; `latest` is refused |
| `SOVARIA_LOCAL_API_PORT`, `…_DB_PORT`, `…_CONSOLE_PORT`, `…_MAIL_PORT` | 54321, 54322, 54323, 54324 | Host ports |
| `SOVARIA_LOCAL_BIND` | `127.0.0.1` | Loopback address the ports are published on (loopback only) |

## In CI

GitHub Actions:
```text
- run: pipx install sovaria-cli
- run: sov start --no-env-file
- run: npm test
  env:
    SOVARIA_URL: http://localhost:54321
    SOVARIA_ANON_KEY: svr_local_anon_5a0f1c8e2b7d4e6f9a3c1b5d7e9f0a2c
- run: sov stop --reset --yes
  if: always()
```
