---
title: Configuration
description: Variables several services share. Set the same values in each.
---

A service validates its environment at start and refuses to boot on an invalid value. Leave an optional variable out rather than empty: `KEY=` sets an empty string, which fails validation.

| Group                                      | api | api-ingest | mcp | worker-errors | worker-jobs |
| ------------------------------------------ | :-: | :--------: | :-: | :-----------: | :---------: |
| [PostgreSQL](#postgresql)                  |  ✓  |     ✓      |  ✓  |       ✓       |      ✓      |
| [ClickHouse](#clickhouse)                  |  ✓  |     ✓      |  ✓  |       ✓       |      ✓      |
| [Redis](#redis)                            |  ✓  |     ✓      |  ✓  |       ✓       |             |
| [Object storage](#object-storage)          |  ✓  |            |     |       ✓       |      ✓      |
| [Ingest queue](#ingest-queue)              |     |     ✓      |     |       ✓       |             |
| [Proxies](#proxies)                        |  ✓  |     ✓      |  ✓  |               |             |
| [Integrations](/self-hosting/integrations) |  ✓  |            |     |               |      ✓      |
| [Email](#email)                            |     |            |     |               |      ✓      |
| [Logging](#logging)                        |  ✓  |     ✓      |  ✓  |       ✓       |      ✓      |

## PostgreSQL

| Variable                        | Required | Default | Description                                                                          |
| ------------------------------- | :------: | ------- | ------------------------------------------------------------------------------------ |
| `DATABASE_URL`                  |   yes    |         | Connection string, such as `postgresql://openperf:openperf@localhost:5432/openperf`. |
| `DATABASE_STATEMENT_TIMEOUT_MS` |    no    | `60000` | Statement timeout, 1000 to 600000. Workers only.                                     |

## ClickHouse

| Variable                                | Required | Default      | Description                                          |
| --------------------------------------- | :------: | ------------ | ---------------------------------------------------- |
| `CLICKHOUSE_URL`                        |   yes    |              | HTTP endpoint, such as `http://localhost:8123`.      |
| `CLICKHOUSE_USER`                       |   yes    |              | User name.                                           |
| `CLICKHOUSE_PASSWORD`                   |   yes    |              | Password.                                            |
| `CLICKHOUSE_DATABASE`                   |   yes    |              | Database name.                                       |
| `CLICKHOUSE_MAX_EXECUTION_TIME_SECONDS` |    no    | `60`         | Query timeout.                                       |
| `CLICKHOUSE_MAX_MEMORY_USAGE`           |    no    | `1073741824` | Memory per query, in bytes.                          |
| `CLICKHOUSE_EXTERNAL_GROUP_BY_BYTES`    |    no    | `536870912`  | `GROUP BY` memory before spilling to disk, in bytes. |
| `CLICKHOUSE_EXTERNAL_SORT_BYTES`        |    no    | `536870912`  | Sort memory before spilling to disk, in bytes.       |
| `CLICKHOUSE_MAX_CONCURRENT_READS`       |    no    | no limit     | Concurrent queries per process; the rest wait.       |

## Redis

| Variable          | Required | Description                                                                                                              |
| ----------------- | :------: | ------------------------------------------------------------------------------------------------------------------------ |
| `REDIS_STATE_URL` |   yes    | Ingest queues, rate limits and idempotency keys. Run it with `maxmemory-policy noeviction`, or queued telemetry is lost. |
| `REDIS_CACHE_URL` |   yes    | Query and project key cache. Eviction is fine. Not read by worker-errors.                                                |

## Object storage

An S3-compatible bucket for source maps, logos and avatars. Without `STORAGE_S3_BUCKET` uploads are refused, browser stacks stay minified and project cleanup skips the bucket.

| Variable                       | Description                                           |
| ------------------------------ | ----------------------------------------------------- |
| `STORAGE_S3_BUCKET`            | Bucket name. Turns object storage on.                 |
| `STORAGE_S3_ENDPOINT`          | Endpoint of a non-AWS store, such as RustFS or MinIO. |
| `STORAGE_S3_REGION`            | Region.                                               |
| `STORAGE_S3_ACCESS_KEY_ID`     | Access key.                                           |
| `STORAGE_S3_SECRET_ACCESS_KEY` | Secret key.                                           |

All are optional. The local RustFS from `docker compose` uses endpoint `http://localhost:9000`, bucket `openperf`, region `us-east-1`, key `openperf` and secret `openperf-secret`.

## Ingest queue

How Redis queues drain into ClickHouse: logs and spans in `api-ingest`, errors in `worker-errors`. All optional.

| Variable                       | Default    | Description                                                                      |
| ------------------------------ | ---------- | -------------------------------------------------------------------------------- |
| `INGEST_QUEUE_LIMIT`           | `10000`    | Undelivered entries per table above which intake answers 429. api-ingest only.   |
| `INGEST_REQUEST_MAX_BYTES`     | `33554432` | Size of the rows of one request above which intake answers 413. api-ingest only. |
| `INGEST_BATCH_MAX_ENTRIES`     | `256`      | Entries per insert, up to 1000.                                                  |
| `INGEST_BATCH_MAX_BYTES`       | `16777216` | Bytes per insert.                                                                |
| `INGEST_DRAIN_IDLE_MS`         | `100`      | Sleep when the queue is empty.                                                   |
| `INGEST_INSERT_ATTEMPTS`       | `3`        | Fast retries of one insert.                                                      |
| `INGEST_RETRY_BASE_MS`         | `250`      | Delay before the first fast retry.                                               |
| `INGEST_OUTAGE_BACKOFF_MS`     | `1000`     | First pause while ClickHouse is unreachable.                                     |
| `INGEST_OUTAGE_MAX_BACKOFF_MS` | `30000`    | Longest pause while ClickHouse is unreachable.                                   |
| `INGEST_RETRY_BACKOFF_MS`      | `5000`     | First delay before retrying a batch ClickHouse rejected.                         |
| `INGEST_RETRY_MAX_BACKOFF_MS`  | `300000`   | Longest delay before retrying a rejected batch.                                  |
| `INGEST_DEAD_LETTER_AFTER_MS`  | `86400000` | Time a batch may keep failing before it moves to `ingest:dead:<table>`.          |
| `INGEST_DEAD_LETTER_LIMIT`     | `10000`    | Dead letter capacity. When full, rejected batches stay queued.                   |

## Proxies

| Variable          | Default    | Description                                                                                                            |
| ----------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------- |
| `TRUSTED_PROXIES` | `loopback` | Comma-separated IPs, CIDRs, `loopback`, `linklocal` or `uniquelocal` trusted for `x-forwarded-for` and `x-request-id`. |

List every proxy and load balancer in front of the service, and `web` for `api`. Otherwise all clients share one address and one rate limit.

## Email

Sign-in codes, alerts and invitations go through [Resend](https://resend.com). Without a key, emails are skipped. Unless `NODE_ENV` of `worker-jobs` is `production`, skipped emails, sign-in codes included, are written to its log. In production, set up Resend or GitHub or Google [sign-in](/self-hosting/services/api#sign-in).

| Variable         | Description                                                                      |
| ---------------- | -------------------------------------------------------------------------------- |
| `RESEND_API_KEY` | Resend API key.                                                                  |
| `EMAIL_FROM`     | Sender, such as `OpenPerf <alerts@example.com>`. Required with `RESEND_API_KEY`. |

## Logging

Services log JSON lines to stdout. See [Logs](/self-hosting/operations#logs).

| Variable    | Default | Description                                                         |
| ----------- | ------- | ------------------------------------------------------------------- |
| `LOG_LEVEL` | `info`  | Lowest level: `trace`, `debug`, `info`, `warn`, `error` or `fatal`. |
