# Deploy to GizStack

A deploy puts your app at its own address, `https://NAME.giz.sh`. It checks the code, runs the
tests, builds the program and publishes it into the running app. The old code serves until then, and
keeps serving when the change is refused. Measured in
production, a change reaches an open page in 1.86–1.96 s, and the page keeps what people typed.

## Deploy from the console

:::status{of="deploy-console"}
:::

:::steps
1. [Sign up](/signup) and open your organization.
2. Describe an app, or choose one of the 20 starters. GizStack writes `app.giz` and
   `app.test.giz`.
3. Open the **Code** tab. Edit the code, then press **Deploy**.
4. The checks and the tests must pass. Then the app is live at its address, and the
   **Deployments** area lists the deploy.
5. Open the **Logs** area to read the app's requests and errors, and the **Data** area to read its
   records.
:::

## Deploy from the terminal

:::status{of="deploy-cli"}
:::

A deploy from the terminal is one HTTPS request with a token. [Sign in](/login), open
[your terminal token](/token) and paste its line into the terminal:

```sh
export GIZ_TOKEN=…
```

With GizStack installed, `giz deploy` in an empty folder makes a project in your first team, at a
new address, publishes a guestbook with its own database, and writes its source to `app.giz`:

```sh
mkdir my-app && cd my-app
giz deploy
```

```text
Live at https://nova-orbit-42.giz.sh (version 1)
Wrote its source to app.giz.
Deploy a change: giz deploy (this folder deploys to nova-orbit-42.giz.sh)
```

Edit `app.giz` (and `app.test.giz`) and run `giz deploy` again. The folder remembers its app in
`.gizstack/app`; `--app NAME` deploys elsewhere, and file arguments send other files. A folder with
a program (`main.giz`) and no `app.giz` is refused: a program runs in a terminal (`giz run`). The
command exits with 1 when a change is refused.

Without the CLI, the same requests are curl. The first deploy needs no file:

```sh
curl -sS --fail-with-body https://gizstack.com/deploy -H "Authorization: Bearer $GIZ_TOKEN" -d ''
```

```text
Live at https://nova-orbit-42.giz.sh (version 1)
Get its source:  curl -sS --fail-with-body 'https://gizstack.com/deploy?app=nova-orbit-42' -H "Authorization: Bearer $GIZ_TOKEN" -o app.giz
Deploy a change: curl -sS --fail-with-body https://gizstack.com/deploy -H "Authorization: Bearer $GIZ_TOKEN" --data-urlencode app=nova-orbit-42 --data-urlencode source@app.giz
```

Run the two printed commands: the first saves `app.giz`, and the second deploys your change of it.

| Form field | Contents |
| --- | --- |
| `app` | The address: `app=NAME` is `https://NAME.giz.sh`. A free name makes a new project; empty picks one. |
| `source` | `app.giz`. Empty publishes the guestbook. |
| `tests` | `app.test.giz`, run before the version goes live. `GET /deploy?app=NAME&file=tests` prints the current one. |
| `summary` | What changed, shown in the Deployments area. |
| `preview` | `1` publishes to `https://NAME--preview.giz.sh` instead (`giz deploy --preview`); the live app does not change. |

- `app.giz` is one GizWeb module that exports `routes(): Vec<S.Route>`. It imports `./stack.giz`,
  which GizStack puts next to it, so the deploy is where it is checked. A rejected deploy answers
  422 with the compiler's words, and the running version stays.
- A deploy also repairs an app whose running version no longer starts: the new code goes in and
  starts fresh, or the old files come back and the deploy is refused.
- A deploy that takes longer than 20 s, such as the first build of an app (a few minutes), prints
  `Building …` and a dot every 10 s, then its answer. Its HTTP status is then 200, so read the last line.
- Each failure says what to do: 401 without a valid token, 409 for an address another team has.
- The token is your session: it ends when you sign out, and after 30 days.

## Change it live

Each deploy replaces the running code. The rules:

| A change to | What happens |
| --- | --- |
| A function body | Live at once. Calls that run finish on the code they started with. |
| A page | Open pages get a patch. Typed text and focus stay. |
| A record type | The table follows: added fields get columns, `@was` renames keep data. A change that loses data is refused. |
| Named state (`gizlang:live`) | It stays, and migrates field by field when its type changes. |

`giz live` gives the same behavior on your computer, with no deploy.

## Previews and rollback

:::status{of="previews"}
:::

- Once an app is live, the console's builder publishes each change as a preview at
  `https://NAME--preview.giz.sh`; `giz deploy --preview` and the code tab's **Preview** box do the same.
  A preview starts on a copy of the live data and keeps its own changes. The live app is unchanged until
  you press **Promote to live** in the **Preview** area.
- **Roll back** in the **Deployments** area publishes an earlier version's source and tests again, as a
  new deployment. The data stays: data lives longer than code.
- From the terminal, `giz api listProjects` lists your apps with their latest deployments, and
  `giz api rollback deployment=ID` publishes one of them again. `giz api` runs any console
  operation by name with your terminal token (`giz api` alone lists them and their fields), as MCP and
  agents do.

## Custom domains

:::status{of="domains"}
:::

```sh
giz secrets set STRIPE_KEY
```

- In the console, open the app's **Settings**, then **Domains**, and add the domain. At your DNS provider, point it at
  `NAME.giz.sh` (a CNAME record) and add the TXT record `_giz-verify.DOMAIN` with the value the console shows. Press
  **Verify**: the domain serves the app from then on. One project holds a domain; names under `giz.sh` and
  `gizstack.com` are the platform's.
- The builder can do the same (addDomain, verifyDomain, removeDomain); a removal waits for your approval.
- HTTPS for your own domain and `giz domains` in the terminal are not available yet.
- A secret is write-only: the app reads it, and nobody can read it back.

## Connect to the database

:::status{of="managed-db"}
:::

Every app has its own GizDB database. `giz db url` prints its connection string for `psql` and
every PostgreSQL driver:

```sh
psql "$(giz db url)" -c "SELECT count(*) FROM appdata_notes"
```

## Limits

| Limit | Value |
| --- | --- |
| Storage for each app | 1 GiB by default. Past it, writes are refused and reads go on. |
| Backups | Each app's database is backed up and the backup is checked. |
