---
title: "Configuration"
description: "Every PUG_* environment variable the server and workers read, with defaults."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.pug.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

Environment variables for the **backend** (the server and workers). The dashboard is configured separately at build time — see [Dashboard](/self-hosting/dashboard).

Copy `.env.example` from the repo root as your starting point and fill in the values for your environment. Every `pug` command loads `.env` if present, then falls back to the process environment — so in production you can skip the file and inject these variables directly.

```bash
cp .env.example .env
```

The sections below document every variable, grouped by concern. **Required** variables must be set; the server will not start correctly without them.

## Stores

The backend requires four backing services. See [Requirements](/self-hosting/requirements) for compatible versions and ports.

| Variable | Required? | Default / Example | Description |
|----------|-----------|-------------------|-------------|
| `DATABASE_URL` | Yes | `postgres://postgres:postgres@localhost:5433/pug?sslmode=disable` | Postgres connection string (DSN). Standard `postgres://` URL including database name and `sslmode`. |
| `CLICKHOUSE_URL` | Yes | `clickhouse://default:@localhost:9000/pug` | ClickHouse connection string using the native protocol (`clickhouse://`). |
| `NATS_URL` | Yes | `nats://localhost:4222` | NATS server URL. JetStream must be enabled on the server (`--jetstream`). |
| `REDIS_URL` | Yes | `redis://localhost:6380` | Dragonfly (Redis-compatible) connection URL. Dev default maps host port 6380 to container port 6379. |

## Server

| Variable | Required? | Default / Example | Description |
|----------|-----------|-------------------|-------------|
| `PUG_SERVER_PORT` | No | `3000` | Port the Connect RPC API server listens on. |
| `PUG_JWT_SECRET_KEY` | Yes | _(generate with `openssl rand -hex 32`)_ | Secret used to sign and verify dashboard JWTs. Use a long random string and never reuse it between environments. |
| `PUG_CORS_ORIGINS` | No | `http://localhost:5173` | Comma-separated list of allowed CORS origins (e.g. `https://app.example.com`). **Must include your dashboard's origin.** When set to `*`, credentials are **not** sent per the CORS spec — set specific origins to enable credentialed requests. |
| `PUG_DASHBOARD_BASE_URL` | No | `http://localhost:5173` | Base URL of the dashboard, used when constructing links in outgoing emails (magic-link, invites, notifications). |
| `PUG_OAUTH_GOOGLE_CLIENT_ID` | No | _(empty)_ | Google OAuth client ID for "Sign in with Google". Leave empty to disable. **Must match the dashboard's `VITE_GOOGLE_CLIENT_ID`.** |

## Workers

| Variable | Required? | Default / Example | Description |
|----------|-----------|-------------------|-------------|
| `PUG_WORKER_HEALTH_ADDR` | No | `:8090` | Address each worker process serves its `/healthz` (liveness) and `/readyz` (readiness) probes on. Set to `off` to disable. When running several worker binaries on one host, give each a distinct port. `pug dev` forces this off. See [Health checks](/self-hosting/deployment#health-checks). |

## Email

Pug sends transactional email (magic links, invites, notifications). Configure a provider and the sender identity before users can sign in.

| Variable | Required? | Default / Example | Description |
|----------|-----------|-------------------|-------------|
| `PUG_EMAIL_FROM` | Yes | `noreply@example.com` | From address for all outgoing email. |
| `PUG_EMAIL_REPLY_TO` | No | _(empty)_ | Reply-To address. Leave empty to omit the header. |
| `PUG_EMAIL_LOGO_URL` | No | `https://pug.sh/logo.png` | URL of a logo image shown in the email header. When empty, a wordmark-only header is rendered. |
| `PUG_EMAIL_PROVIDER` | Yes | `resend` | Email delivery provider. Supported values: **`resend`** or **`ses`**. |
| `PUG_RESEND_API_KEY` | Conditional | — | Resend API key. Required when `PUG_EMAIL_PROVIDER=resend`. |
| `PUG_SES_REGION` | Conditional | `us-east-1` | AWS region for SES. Optional when `PUG_EMAIL_PROVIDER=ses` if `AWS_REGION` is already set. |
| `AWS_REGION` | Conditional | `us-east-1` | Standard AWS SDK region. Required for SES. |
| `AWS_ACCESS_KEY_ID` | Conditional | — | Standard AWS SDK access key. Required for SES. |
| `AWS_SECRET_ACCESS_KEY` | Conditional | — | Standard AWS SDK secret key. Required for SES. |
| `AWS_SESSION_TOKEN` | No | _(empty)_ | AWS session token for temporary (STS) credentials. Optional. |
| `PUG_EMAIL_PROVIDER_SECRET_KEY` | No | _(empty)_ | Encryption key for per-tenant email provider configuration stored at rest. Generate with `openssl rand -base64 32`. Leave empty to disable per-tenant providers — the operator-level provider handles all sends. |

> You can preview any transactional email without sending it: `pug email preview magic_link` renders it to HTML on stdout. See the [CLI reference](/self-hosting/cli#email-preview).

## Telemetry

The backend emits OpenTelemetry traces, metrics, and logs. **Export mode is auto-detected once at process start:** if an OTLP endpoint variable is set, Pug exports to that collector; otherwise it logs to stdout as plain text (no collector needed).

| Variable | Required? | Default / Example | Description |
|----------|-----------|-------------------|-------------|
| `OTEL_EXPORTER_OTLP_ENDPOINT` | No | _(empty)_ | OTLP collector endpoint, e.g. `http://localhost:4317`. When set, Pug exports traces/metrics/logs there. When unset, it logs to stdout. |
| `OTEL_SERVICE_NAME` | No | `pug` | Service name reported in OpenTelemetry spans. Only used when exporting via OTLP. |

The standard OTEL SDK environment variables (`OTEL_EXPORTER_OTLP_HEADERS`, `OTEL_EXPORTER_OTLP_PROTOCOL`, …) are also honored. For a ready-made local collector, see [`make clickstack`](/self-hosting/development#observability-clickstack).

## Demo dataset (optional)

Off by default — these power the public "Pug & Pals" demo and are irrelevant to a normal self-host. `PUG_DEMO_ENABLED` is the single switch: it gates both the `demo` worker and the credential-less demo sign-in RPC on the server. Leave it `false` everywhere unless you're intentionally hosting a public demo.

| Variable | Default | Description |
|----------|---------|-------------|
| `PUG_DEMO_ENABLED` | `false` | Master switch. When `true`, the `demo` worker streams synthetic traffic and `pug server` exposes a read-only demo sign-in. Set on **every** pod (server + worker) of a demo deployment. |
| `PUG_DEMO_PEAK_SESSIONS_PER_MIN` | `6` | Peak sessions/min at the busiest hour (≈30–50k events/day at `6`); off-peak follows a diurnal curve. |
| `PUG_DEMO_SEED_COUNT` | `500000` | One-time backfill volume when the demo project is empty. |
| `PUG_DEMO_SEED_BATCH` | `10000` | ClickHouse insert batch size for the backfill. |

## Minimal `.env` example

A minimal configuration for local development. Production deployments need real secrets and a working email provider.

```env
# Stores
DATABASE_URL=postgres://postgres:postgres@localhost:5433/pug?sslmode=disable
CLICKHOUSE_URL=clickhouse://default:@localhost:9000/pug
NATS_URL=nats://localhost:4222
REDIS_URL=redis://localhost:6380

# Server
PUG_SERVER_PORT=3000
PUG_JWT_SECRET_KEY=change_me_use_openssl_rand_hex_32
PUG_CORS_ORIGINS=http://localhost:5173
PUG_DASHBOARD_BASE_URL=http://localhost:5173

# Email (Resend)
PUG_EMAIL_FROM=noreply@example.com
PUG_EMAIL_PROVIDER=resend
PUG_RESEND_API_KEY=re_your_resend_api_key
```

## Further reading

- [Requirements](/self-hosting/requirements) — backing services, ports, and sizing
- [Deployment](/self-hosting/deployment) — production build, run, and hardening
- [Dashboard](/self-hosting/dashboard) — the separate `VITE_*` build-time config

Source: https://docs.pug.sh/self-hosting/configuration/index.mdx
