# Databases

> Creating, attaching, and inspecting managed PostgreSQL databases from the Tarout CLI

# Databases

> **Preflight - check auth first.** Run `tarout whoami --json`. If it does not
> return `success: true`, authenticate with the table in
> [start.md](https://tarout.sa/docs/for-ai/start.md)
> before running anything on this page - every command below fails without a
> credential, and the failure reads like a broken deploy rather than a missing
> login.

Tarout runs managed PostgreSQL 16 with connection pooling. **Create the database
the code needs as part of the deploy - announce it, don't ask.**

MySQL is not available: `--database mysql` and `tarout db create --type mysql`
fail with "MySQL databases are not available yet". If the code is written for
MySQL, tell the user and ask whether to move the app to PostgreSQL before
creating anything.

There is no version flag and no credential to choose: Tarout generates the
database name, user, and password.

## Create it during the first deploy (preferred)

Letting `tarout deploy` create and attach the database means the connection
variables are injected *before* the app boots:

```sh
tarout deploy --wait --database postgres
```

The CLI picks the tier from the project's subscription and uses an open database
slot when there is one. When a paid project has no open slot:

- In an interactive terminal, the CLI adds the cheapest tier for the plan
  (Starter → `db.starter`, Pro → `db.pro`) and opens the payment page.
- With `--json`, `--yes`, or no TTY (the usual agent run), it buys nothing and
  returns `NEEDS_UPGRADE` listing every database tier with its
  `tarout billing addon:buy ...` command, plus a plan upgrade. Ask the user
  which one to run, then run it; the checkout page it opens is the payment
  approval. See [billing.md](https://tarout.sa/docs/for-ai/billing.md).

A free project whose one database is already in use also gets `NEEDS_UPGRADE`;
reusing that database with `tarout deploy --wait --reuse-database auto` is
often the better fix.

## Attach one to an existing app

```sh
tarout db create my-db --type postgres
tarout db attach <db-id-or-name> <app-id>
```

`db attach` does three things and only returns when all three finish:

1. inserts the link row,
2. writes `DATABASE_URL` / `DIRECT_DATABASE_URL` / `PGHOST` and friends into the
   app's environment,
3. restarts the app so it picks up the new environment - **no redeploy needed**.

`tarout db create` blocks until the database reports `status: done`, so there is
nothing to poll.

## Inspect and query

```sh
tarout db list
tarout db info <db>                        # host, port, database, user (password masked)
tarout db connect <db>                     # interactive psql shell (needs psql installed)
tarout db tables <db>
tarout db preview <db> <table>
tarout db sql <db> "select 1"
tarout db analytics <db>                   # size, connections, cache hit rate
```

The full external connection string, password and `?sslmode=require`
included, is `data.externalConnectionString` in `tarout db info <db> --json`.
It is a credential: ask before printing it. Hand it out exactly as returned;
never rebuild it with a guessed port or user, or without `sslmode`. For verified
TLS the user downloads the CA certificate from the database page and replaces
`sslmode=require` with `sslmode=verify-full&sslrootcert=<path-to-ca>`.

`tarout db sql` rejects role, permission, and database-level statements
(`CREATE ROLE`, `CREATE USER`, `ALTER ROLE`, `GRANT`, `REVOKE`,
`CREATE DATABASE`, `DROP DATABASE`), so extra users such as a read-only role
cannot be created.

**Ask the user first** before `tarout db sql` with a destructive statement
(`DROP`, `DELETE`, `TRUNCATE`, `ALTER`) or before `tarout db delete`. On an
operator-tier API key those calls will not run immediately anyway - they create
an approval request, see [troubleshoot.md](https://tarout.sa/docs/for-ai/troubleshoot.md). Other
SQL (`SELECT`, `INSERT`, `UPDATE`, `CREATE`) runs straight away.

## Changing tiers

```sh
tarout db upgrade <db> --plan <starter|standard|pro>
tarout db downgrade <db> --plan <starter|standard>
```

A tier change copies the data to the new tier, and the database is read-only
(writes fail) until the copy finishes. Tell the user before starting one on a
live app. An upgrade that carries a charge opens checkout; a downgrade applies
immediately with no refund.

## Backups

Tarout backs up its shared database hosts daily for disaster recovery, but only
Tarout can restore those, and only for a whole host. **Do not tell the user a
database is backed up automatically.** Per-database backups go to the user's own
S3-compatible bucket on a schedule they set up:

```sh
tarout destinations list                   # existing backup destinations
tarout destinations create --name <name> --provider s3 --bucket <bucket> \
  --region <region> --endpoint <https-url> --access-key <key> --secret-key <secret>
tarout backups create --postgres-id <db-id> --destination-id <destination-id> \
  --database <database-name> --schedule "0 2 * * *" --keep 7
tarout db backups <db> --json              # this database's schedules and backupIds
tarout backups run <backup-id>             # run a backup now
tarout backups files <destination-id>      # list saved files
tarout backups download-url <destination-id> <file>
```

- `<db-id>` is the database's full `id` from `tarout db list --json`, and `--database`
  is the database name that `tarout db info <db>` prints. Pass every flag, or the
  CLI stops to prompt.
- `--keep` keeps only the newest N files; `--schedule` is a cron expression.
- `--provider` accepts `s3` (AWS or any S3-compatible service), `gcs`,
  `wasabi`, `minio`, or `tarout-object-storage`.
- `destinations create` needs the user's own bucket credentials: ask for them,
  never invent a destination.
- Restore is dashboard-only (`tarout backups restore` exits with an error):
  send the user to the database's **Backups** tab.

Connection details for an attached database are already in the app's environment;
read them with `tarout env <app> list`. Revealing a value prints a credential, so
ask before running `tarout env <app> reveal DATABASE_URL`.

---

## Every Tarout agent guide

- [Start Here (Agents)](https://tarout.sa/docs/for-ai/start.md)
- [Overview](https://tarout.sa/docs/for-ai.md)
- [Deploying an app](https://tarout.sa/docs/for-ai/deploy.md)
- [Object storage](https://tarout.sa/docs/for-ai/storage.md)
- [Custom domains](https://tarout.sa/docs/for-ai/domains.md)
- [Plans and upgrades](https://tarout.sa/docs/for-ai/billing.md)
- [Troubleshooting](https://tarout.sa/docs/for-ai/troubleshoot.md)
- [Agent Onboarding](https://tarout.sa/docs/for-ai/onboarding.md)
- [CLI Reference](https://tarout.sa/docs/for-ai/cli-reference.md)
- [CLI JSON Schema](https://tarout.sa/docs/for-ai/cli-json-schema.md)

Whole corpus in one file: https://tarout.sa/llms-full.txt · index: https://tarout.sa/llms.txt
Any docs page is raw markdown at the same URL + `.md`. Short link to the entry point: https://tarout.sa/deploy.md
