# Built-ins

Postgres, Redis, S3 storage, email, ClickHouse, OIDC sign-in and certificates, provisioned per sandbox and per environment.

Each entry under `managed` is `<name>: { type: <type>, ...options }`. The name is the host inside the sandbox (`db:5432`), so it can't also be a service's name. Each sandbox gets its own instance of every entry, with its own generated credentials.

| `type` | Attributes for `${<name>.<attr>}` | Variables from `depends_on: [<name>]` | Options |
| --- | --- | --- | --- |
| `postgres` | `url`, `host`, `port`, `user`, `password`, `database` | `DATABASE_URL`, `PGHOST`, `PGPORT`, `PGUSER`, `PGPASSWORD`, `PGDATABASE` | `version`: 15, 16 (default) or 17 |
| `redis` | `url`, `host`, `port` | `REDIS_URL` | `version` (default 7) |
| `s3` | `endpoint`, `public_endpoint`, `region`, `access_key_id`, `secret_access_key`, `bucket.<name>` | `AWS_ENDPOINT_URL_S3`, `AWS_REGION`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` | `buckets: [name, ...]` |
| `email` | `url`, `smtp_host`, `smtp_port`, `smtp_user`, `smtp_password` | `SMTP_URL`, `SMTP_HOST`, `SMTP_PORT` | |
| `clickhouse` | `url`, `native_url`, `user`, `password`, `database` | `CLICKHOUSE_URL`, `CLICKHOUSE_USER`, `CLICKHOUSE_PASSWORD`, `CLICKHOUSE_DB` | `version` (default 26.8) |
| `auth` | `issuer`, `client_id`, `client_secret`, `jwks_url` | `OIDC_ISSUER`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET` | `redirect_uris`, `initiate_login_uri` |
| `certificate` | `cert_file`, `key_file`, `ca_file`; with `keystores: [pkcs12]` also `pkcs12_file`, `pkcs12_password` | None | `common_name`, `dns_names`, `duration`, `keystores` |

## Protocols [#protocols]

They all speak standard protocols, so moving from a hosted Postgres, Redis, S3 or ClickHouse is a URL change. There is no MySQL, MongoDB or RabbitMQ: run one as a service (`image: mysql:8.0, ports: { mysql: 3306 }`), and list it in a migration job's `depends_on` (see [jobs](/manifest/jobs)). Celery, BullMQ and Sidekiq run on Redis.

## Where each built-in runs [#where-each-built-in-runs]

| Type | Sandboxes | Staging and production |
| --- | --- | --- |
| `postgres` | Postgres in the sandbox, configured like Cloud SQL | Cloud SQL, one database and user per environment |
| `redis` | Redis in the sandbox | Redis |
| `s3` | S3 storage in the sandbox, with each listed bucket | GCS buckets |
| `email` | The sandbox inbox: every message is captured | Your email provider's SMTP |
| `clickhouse` | ClickHouse in the sandbox | ClickHouse |
| `auth` | An OIDC issuer per sandbox, with its own users | An OIDC issuer per environment |
| `certificate` | Issued by the sandbox's own CA through cert-manager | Issued by the environment's CA |

## Postgres [#postgres]

**Postgres** behaves like Google Cloud SQL, which staging and production use. Your app's user owns its database but is not a superuser: it has CREATEDB and CREATEROLE and is a member of `cloudsqlsuperuser`. Cloud SQL's contrib extensions are available, `vector` (pgvector) included, and the app can create them. Any other extension, or a migration that needs a superuser, fails in the sandbox, before it would fail in production. It accepts TLS and plain connections. The sandbox certificate is self-signed: a client that doesn't verify it (`ssl: { rejectUnauthorized: false }`, libpq's `sslmode=require`) connects, and one that does needs `sslmode=disable` in sandboxes.

## S3 storage [#s3-storage]

**S3 storage** speaks the S3 protocol, with each bucket in `buckets` created per sandbox.
- Use `public_endpoint` for any URL a browser follows, such as presigned uploads and downloads. Your services can reach it too, so it works everywhere.
- With the AWS JS SDK v3, set `forcePathStyle: true` and `requestChecksumCalculation: 'WHEN_REQUIRED'`.
- Each listed bucket allows `GET`, `PUT`, `POST` and `HEAD` from the sandbox's own public URLs (CORS), which presigned browser uploads need. To set other rules, call `PutBucketCors` from a `deploy` job.

## Email [#email]

Email is SMTP. `url` is `smtp://[user:password@]host:port`; in sandboxes it is `smtp://<name>:1025`, with no TLS and an empty user and password. The inbox accepts any user and password, so an app that always sends credentials works with placeholders such as `SMTP_USER: sandbox`. All mail the app sends lands in the sandbox's inbox, whatever the recipient. Read it with `parity inbox`.

If your app sends through a provider's HTTP API, switch it to SMTP: Resend, Postmark, SendGrid, Mailgun and Amazon SES all accept SMTP, so one code path sends in sandboxes and in production.

## Auth [#auth]

**Auth** is an OpenID Connect provider with its own users per sandbox. Its token endpoint accepts the client secret either way OAuth allows (`client_secret_basic` or `client_secret_post`), so any OIDC library works with its defaults.

```yaml
managed:
  auth:
    type: auth
    redirect_uris: [{ service: web, path: /auth/callback }]
    initiate_login_uri: { service: web, path: /login }
```

`redirect_uris` registers your app's callbacks. `initiate_login_uri` is where sign-in links land. Create users with `parity auth user create` and get a one-time sign-in link with `parity signin <email>`.

## Certificates [#certificates]

An X.509 certificate issued by the sandbox's own certificate authority, for document signing, mutual TLS or a TLS listener inside the sandbox.

```yaml
managed:
  signing: { type: certificate, keystores: [pkcs12] }
services:
  web:
    env:
      SIGNING_P12:          ${signing.pkcs12_file}
      SIGNING_P12_PASSWORD: ${signing.pkcs12_password}
```

- The `_file` attributes are file paths. A service (and its jobs) that references the entry gets the files mounted read-only under `/var/run/secrets/parity/<name>/`.
- `ca_file` is the sandbox's own root, so two sandboxes never trust each other's certificates.
- `common_name` (default `<name>, sandbox <id>`) and `dns_names` may use `${sandbox.id}` and `${sandbox.domain}`. `duration` is 1h to 8760h, default 2160h.
- There's no standard variable name for a certificate, so `depends_on` is refused for this type. Name the variables your app reads.
