Configuration
Configuration guides for customizing PostgresAI monitoring components.
Components
| Component | Purpose | Configuration scope |
|---|---|---|
| pgwatch | Metrics collection | Collection intervals, custom metrics |
| VictoriaMetrics | Time-series storage | Retention, storage, scrape settings |
| Grafana | Visualization | Dashboards, data sources, authentication |
| Alerting | Notifications | Alert rules, notification channels |
Configuration methods
CLI installation
Configuration is stored in the monitoring directory .env file. update-config migrates .env
and regenerates the pgwatch sources.yml. Since 0.17 it also applies .env to a running
sink-prometheus, so the VM_* flags below take effect; it does not restart any other service, so
keys read by those services at startup take effect only once the service is recreated:
# Example .env overrides (default VM_RETENTION_PERIOD is 336h ≡ 14 days)
VM_RETENTION_PERIOD=30d
VM_QUERY_DURATION=30s
VM_MAX_CONCURRENT_REQUESTS=16
postgresai mon update-config
# Since 0.17, update-config already applies these to a running sink-prometheus.
# On older CLIs, recreate it yourself:
docker compose up -d --force-recreate sink-prometheus
Docker Compose
Configuration is passed through docker-compose.yml and the generated .env file:
# Example overrides (default VM_RETENTION_PERIOD is 336h ≡ 14 days)
VM_RETENTION_PERIOD=30d
VM_QUERY_DURATION=30s
VM_MAX_CONCURRENT_REQUESTS=16
Helm
Configuration via values.yaml (see Helm installation):
victoriaMetrics:
retentionPeriod: 336h # default; 14 days
scrapeInterval: 15s
Quick reference
| Setting | Default | Description |
|---|---|---|
| Scrape interval | 15s | How often to collect metrics (victoriaMetrics.scrapeInterval) |
| Retention | 14 days (336h) | How long to keep metrics (VM_RETENTION_PERIOD / victoriaMetrics.retentionPeriod) |
| Query-id mapping retention | 720 hours (30 days) | How long the Flask backend keeps the queryid → query-text mapping (QUERYID_RETENTION_HOURS, a bare integer number of hours — no h suffix) |
Resource limits (per service)
New in 0.15, each monitoring-stack service has optional CPU and memory limits exposed as .env
variables. All of them are optional — leaving them unset preserves the default
laptop/dev sizing and produces no behavior change. Memory limits are in bytes (Docker
Compose mem_limit convention); *_CPUS values are floats (Docker Compose cpus: semantics).
Provisioning playbooks can export production-grade values per VM size class without forking the
compose file.
| Service | CPU variable | Memory variable | Default memory |
|---|---|---|---|
| Demo target database | TARGET_DB_CPUS (0.2) | TARGET_DB_MEM | 768 MiB |
| Demo target standby | TARGET_STANDBY_CPUS (0.2) | TARGET_STANDBY_MEM | 768 MiB |
| Postgres sink | SINK_POSTGRES_CPUS (0.4) | SINK_POSTGRES_MEM | 1 GiB |
| VictoriaMetrics sink | SINK_PROMETHEUS_CPUS (0.75) | SINK_PROMETHEUS_MEM | 1.5 GiB |
| pgwatch (Postgres sink) | PGWATCH_POSTGRES_CPUS (0.35) | PGWATCH_POSTGRES_MEM | 512 MiB |
| pgwatch (Prometheus sink) | PGWATCH_PROMETHEUS_CPUS (0.5) | PGWATCH_PROMETHEUS_MEM | 512 MiB |
| Grafana | GRAFANA_CPUS (0.5) | GRAFANA_MEM | 512 MiB |
| Flask backend | FLASK_CPUS (0.5) | FLASK_MEM | 1 GiB |
| Reporter | POSTGRES_REPORTS_CPUS (1.0) | POSTGRES_REPORTS_MEM | 1.75 GiB |
| cAdvisor (self-monitoring) | CADVISOR_CPUS (0.25) | CADVISOR_MEM | 384 MiB |
| node exporter (self-monitoring) | NODE_EXPORTER_CPUS (0.05) | NODE_EXPORTER_MEM | 96 MiB |
| postgres exporter (self-monitoring) | POSTGRES_EXPORTER_CPUS (0.1) | POSTGRES_EXPORTER_MEM | 128 MiB |
Set the values in the monitoring stack .env. These are Compose cpus: / mem_limit: keys that
only take effect when a container is recreated, so after migrating .env with
postgresai mon update-config recreate the affected services with
docker compose up -d --force-recreate <service> (or set the values before the initial
docker compose up -d for manual installs); update-config does not recreate services, except
that since 0.17 it brings a running sink-prometheus in line with .env. The VictoriaMetrics engine
tuning flags (VM_QUERY_DURATION, VM_MAX_CONCURRENT_REQUESTS, and the 0.17 query guardrails) are
documented under
Query and search tuning.
Config seeding and operator edits
The stack seeds its generated configuration once and guards it with a version marker, so
operator edits to provisioned config persist across restarts and are not silently overwritten.
The reseed is performed by the config-init service: on start it compares the image's /VERSION
against the .pgai-configs-version marker in the config volume, and reseeds only when they
differ. A reseed therefore happens when you recreate the stack on a newer image — i.e. on
docker compose up -d after the image tag (and thus the image version) is bumped, since up -d
recreates config-init from the new image and it then sees the version mismatch. (postgresai mon start runs docker compose up -d only when the stack is stopped — on an already-running stack
it reports Monitoring services are already running and exits without recreating anything — so for
an in-place upgrade of a running stack, run docker compose up -d directly to recreate config-init,
not mon start.) postgresai mon restart does not trigger a reseed: it runs
docker compose restart, which restarts the existing config-init container in place on the
old image, so it still reads the old /VERSION, the marker still matches, and nothing is
re-copied. postgresai mon update-config migrates the .env file (additive required keys),
refreshes the CLI-owned docker-compose.yml to match the stack version for non-git/global
installs (a no-op for git checkouts), and regenerates the pgwatch sources
(docker compose run --rm sources-generator). That run starts config-init first, so after a
PGAI_TAG change it does reseed the volume. Since 0.17 it then runs
docker compose up -d --no-deps sink-prometheus, which recreates a running sink-prometheus only if
its .env values or compose definition changed. That does not reload a re-seeded
prometheus.yml; run docker compose restart sink-prometheus for that. It does not restart Grafana
or the collectors. To force a fresh reseed, remove the version marker from the config volume so
config-init re-copies the image defaults on the next start.
The config-init service is the only one that mounts the volume read-write (at /target); every
long-running service mounts it read-only (/postgres_ai_configs:ro), so you cannot delete the
marker from, say, the Grafana container. The service is also a one-shot init container that exits
immediately, so plain docker exec config-init … fails (the container name is
postgres-ai-config-init and it is not running). Instead, run a throwaway config-init with its
entrypoint overridden to rm (its normal entrypoint is the seeder script, which ignores extra
arguments), then restart:
docker compose run --rm --entrypoint rm config-init /target/.pgai-configs-version
docker compose up -d --force-recreate config-init
docker compose up -d --force-recreate config-init recreates the one-shot config-init container;
with the marker now absent, init-configs.sh reseeds unconditionally. (A plain docker compose up -d
also works — it recreates config-init because nothing else depends on the cleared marker — but the
explicit --force-recreate config-init makes the intent unambiguous.) Do not use postgresai mon start here: on an already-running stack mon start only checks whether the containers are up and, if
they are, prints Monitoring services are already running and exits without running docker compose up -d, so config-init is never recreated and the reseed silently does not happen. Likewise
postgresai mon restart only restarts the existing containers in place and would not re-run the seeder
against the cleared volume. Recreating config-init on a live stack must therefore go through
docker compose up -d directly.
Sections
- pgwatch configuration — Metrics collector settings
- Prometheus/VictoriaMetrics — Time-series storage
- Grafana configuration — Dashboard customization
- Alerting — Alert rules and notifications