Uptrace Configuration Reference
All Uptrace settings live in a single YAML file. This page covers the main options for databases, networking, authentication, processing pipelines, and features. Run uptrace config create to get the full default file.
Configuration file
Creating the config file
Generate a default configuration file:
./uptrace --config=/path/to/config.yml config create
The command writes a random service.secret into a new file that only its owner can read (mode 0600), and it does not overwrite an existing file.
If you write the config by hand, set service.secret to a random value, for example from openssl rand -hex 32. Outside service.env: dev, Uptrace refuses an empty secret and the FIXME placeholder: uptrace serve and uptrace config validate exit with service.secret is the shipped placeholder.
Specify the config file location using either method:
# CLI argument (recommended)
uptrace --config=/etc/uptrace/config.yml serve
# Environment variable
export UPTRACE_CONFIG=/etc/uptrace/config.yml
uptrace serve
If no path is specified, Uptrace defaults to /etc/uptrace/config.yml.
Environment variables
Use environment variables in your YAML configuration for secrets and per-environment overrides:
pg:
addr: ${UPTRACE_PG_ADDR:localhost:5432}
user: ${UPTRACE_PG_USER:uptrace}
password: ${UPTRACE_PG_PASSWORD}
database: ${UPTRACE_PG_DATABASE:uptrace}
| Syntax | Behavior |
|---|---|
${ENV_VAR_NAME} | Simple substitution |
${ENV_VAR_NAME:default_value} | Substitution with fallback |
$$ | Literal $ |
Variables are expanded using Go's os.Expand before YAML parsing.
File layout
Each top-level key is one subsystem or one dependency, for example pg, ch_cluster, listen, auth, or mailer. Two sections group related blocks:
| Section | Holds |
|---|---|
pipelines | One block for each data pipeline: spans, span_links, logs, events, metrics, profiling, service_graph, project_metrics, query_usages |
alerting | The alerting switches, the monitor kinds (metric_monitors, error_monitors), the alert_trends schedule, and incidents |
The OAuth apps live under auth.github and auth.google, and the per-trace overrides under trace.overrides.
Older releases used other keys for some options, for example a top-level spans block instead of pipelines.spans. The old keys still work: Uptrace logs a deprecation warning for each one on startup. Run uptrace config fix to rewrite them.
Fixing deprecated options
uptrace config fix rewrites the deprecated options of the config file to their current keys. Without --write, it prints each fix and a diff, and changes nothing:
uptrace --config=/etc/uptrace/config.yml config fix
spans -> pipelines.spans
metric_monitors -> alerting.metric_monitors
github_oauth -> auth.github
auth.sign_up_disabled -> auth.sign_up
--- /etc/uptrace/config.yml
+++ /etc/uptrace/config.yml (fixed)
@@ -1,12 +1,14 @@
auth:
- sign_up_disabled: true
+ sign_up: false
-github_oauth:
- client_id: ${GITHUB_CLIENT_ID}
- client_secret: ${GITHUB_CLIENT_SECRET}
+ github:
+ client_id: ${GITHUB_CLIENT_ID}
+ client_secret: ${GITHUB_CLIENT_SECRET}
-spans:
- max_threads: 16 # Processing goroutines
+pipelines:
+ spans:
+ max_threads: 16 # Processing goroutines
-metric_monitors:
- max_workers: 8
+alerting:
+ metric_monitors:
+ max_workers: 8
run with --write to apply
The command exits with status 1 when the file has a deprecated option and 0 when it has none, so you can use it as a check in CI or before an upgrade.
To apply the fixes, add --write. Uptrace keeps the original file as config.yml.bak:
uptrace --config=/etc/uptrace/config.yml config fix --write
spans -> pipelines.spans
metric_monitors -> alerting.metric_monitors
github_oauth -> auth.github
auth.sign_up_disabled -> auth.sign_up
wrote /etc/uptrace/config.yml (the original is /etc/uptrace/config.yml.bak)
How the rewrite works:
- It changes only the lines of deprecated options. Comments, key order, formatting, and
${VAR}references stay as they are. Commented-out examples are not changed. - It deletes an option that the current release no longer uses, for example
ch_schema.spans_index.ttl_deleteof v2.0, and prints<option>: removed, it is no longer used. Until you delete it, Uptrace accepts such an option and logs a warning. An option inside a one-line{ ... }table stays in place with a note to edit it by hand. - Before it writes, it checks that the new file gives exactly the same configuration and has no deprecated option left. If the check fails, it writes nothing.
- An option whose value is an environment reference that must be inverted or converted, such as
sign_up_disabled: ${SIGN_UP_OFF}, stays in place with a note to edit it by hand. The command then still exits with status1. - Like
uptrace config validate, it does not connect to any database.
Database configuration
Uptrace uses PostgreSQL for metadata (users, projects, dashboards, alerts) and ClickHouse for high-volume telemetry (spans, logs, metrics).
PostgreSQL
PostgreSQL stores application metadata. This database typically requires only a few megabytes of storage.
pg:
addr: localhost:5432
user: uptrace
password: uptrace
database: uptrace
#tls:
# insecure_skip_verify: true # Only for self-signed certificates
With read replicas:
pg:
addr: primary-host:5432
user: uptrace
password: uptrace
database: uptrace
read_replicas:
- addr: standby-host1:5432
role: read # serves reads in rotation with the primary
- addr: standby-host2:5432
role: standby # takes reads only while nothing else is healthy
Using a connection string:
pg:
dsn: postgresql://user:password@host:5432/database?sslmode=verify-full
ClickHouse
ClickHouse stores telemetry data — spans, logs, and metrics. It's optimized for analytical queries and time-series data.
ch_cluster:
cluster: 'uptrace1'
replicated: false # Enable for automatic failover
distributed: false # Enable for horizontal scaling (Premium only)
shards:
- replicas:
- addr: localhost:9000
user: default
password: ''
database: uptrace
dial_timeout: 3s
write_timeout: 5s
max_retries: 3
max_execution_time: 15s
With replication (3 nodes):
ch_cluster:
cluster: 'uptrace1'
replicated: true
shards:
- replicas:
- addr: clickhouse-1:9000
user: default
password: ''
database: uptrace
- addr: clickhouse-2:9000
user: default
password: ''
database: uptrace
- addr: clickhouse-3:9000
user: default
password: ''
database: uptrace
Using a connection string:
ch_cluster:
shards:
- replicas:
- dsn: clickhouse://your_username:your_password@your_host:9000/your_database
dial_timeout: 3s
write_timeout: 5s
max_retries: 3
max_execution_time: 15s
Advanced ClickHouse settings
Query settings:
ch_cluster:
shards:
- replicas:
- addr: localhost:9000
query_settings:
async_insert: 1
wait_for_async_insert: 1
max_memory_usage: 10000000000 # 10 GB per query
TLS — ClickHouse server side:
<?xml version="1.0" ?>
<clickhouse>
<tcp_port_secure>9440</tcp_port_secure>
<openSSL>
<server>
<certificateFile>/etc/clickhouse/certs/chnode.crt</certificateFile>
<privateKeyFile>/etc/clickhouse/certs/chnode.key</privateKeyFile>
<verificationMode>relaxed</verificationMode>
<caConfig>/etc/clickhouse/certs/Uptrace_CA.crt</caConfig>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
</server>
</openSSL>
</clickhouse>
TLS — Uptrace side:
ch_cluster:
shards:
- replicas:
- addr: localhost:9440
user: default
database: uptrace
tls:
ca_file: /etc/clickhouse/certs/Uptrace_CA.crt
cert_file: /etc/clickhouse/certs/chnode.crt
key_file: /etc/clickhouse/certs/chnode.key
insecure_skip_verify: false
ClickHouse Cloud:
ch_cluster:
shards:
- replicas:
- addr: tm849a32za.us-central1.gcp.clickhouse.cloud:9440
user: default
password: your_cloud_password
database: uptrace
tls:
server_name_override: 'tm849a32za.us-central1.gcp.clickhouse.cloud'
Database management
Resetting ClickHouse
Reset the ClickHouse database to apply schema changes or start fresh:
uptrace migrate reset --database ch
uptrace migrate up
reset drops the ClickHouse database and creates it again, empty. up then creates the ClickHouse tables again. PostgreSQL is not changed.
Warning: This deletes all telemetry data (spans, logs, metrics).
Resetting PostgreSQL
Reset the PostgreSQL database to clear metadata:
uptrace migrate reset --database pg
uptrace migrate up
uptrace db seed
reset drops the PostgreSQL database and creates it again, empty. up creates the PostgreSQL tables again, and db seed creates the projects and users of your config. The ClickHouse data stays.
Warning: This deletes all metadata including users, projects, dashboards, and alerts.
To reset both databases at once, run uptrace migrate reset without --database.
Emptying the databases
Delete all data and keep the schema:
# Both databases
uptrace migrate truncate
# Only ClickHouse
uptrace migrate truncate --database ch
truncate keeps the tables and the migration records, so you do not need to run migrate up after it.
Schema configuration
Customize ClickHouse schema settings for performance and storage efficiency. Schema changes require a ClickHouse reset (uptrace migrate reset --database ch, then uptrace migrate up) and delete all existing data.
Storage and compression
ch_schema:
# LZ4: fast, moderate ratio. ZSTD(1): better ratio, slightly slower.
compression: ZSTD(1)
# Storage policies — map tables to storage tiers (SSD, HDD, S3)
spans_index: { storage_policy: hot_storage }
spans_data: { storage_policy: warm_storage }
span_links: { storage_policy: cold_storage }
logs_index: { storage_policy: hot_storage }
logs_data: { storage_policy: warm_storage }
events_index: { storage_policy: hot_storage }
events_data: { storage_policy: warm_storage }
timeseries: { storage_policy: hot_storage }
datapoints: { storage_policy: hot_storage }
Replication setup
Step 1: Configure the ClickHouse cluster with at least 3 replicas. Set internal_replication = true to prevent data duplication.
<clickhouse>
<remote_servers>
<uptrace1>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>clickhouse-1</host>
<port>9000</port>
</replica>
<replica>
<host>clickhouse-2</host>
<port>9000</port>
</replica>
<replica>
<host>clickhouse-3</host>
<port>9000</port>
</replica>
</shard>
</uptrace1>
</remote_servers>
</clickhouse>
Step 2: Enable replication in Uptrace:
ch_cluster:
cluster: 'uptrace1'
replicated: true
shards:
- replicas:
- addr: clickhouse-1:9000
- addr: clickhouse-2:9000
- addr: clickhouse-3:9000
Step 3: Apply with uptrace migrate reset --database ch, then uptrace migrate up.
Step 4: Verify replication status:
SELECT
database,
table,
is_leader,
replica_is_active
FROM system.replicas;
Expected output:
┌─database─┬─table───────────┬─is_leader─┬─replica_is_active────────────────────────┐
│ uptrace │ spans_data │ 1 │ {'replica1':1,'replica2':1,'replica3':1} │
│ uptrace │ spans_index │ 1 │ {'replica1':1,'replica2':1,'replica3':1} │
└──────────┴─────────────────┴───────────┴──────────────────────────────────────────┘
Network configuration
Ports
listen:
http:
addr: ':80' # OTLP/HTTP, REST API, web UI
grpc:
addr: ':4317' # OTLP/gRPC
#tls:
# cert_file: /etc/uptrace/uptrace.crt
# key_file: /etc/uptrace/uptrace.key
gRPC transport and stream lifetime
The gRPC listener accepts OTLP and OTel Arrow telemetry. These transport options rarely need tuning, but are available under listen.grpc:
listen:
grpc:
addr: ':4317'
# Largest message the server accepts (default: 64MiB).
max_recv_msg_size: 67108864
# Per-connection read/write buffers (defaults: 64KiB / 16KiB).
read_buffer_size: 65536
write_buffer_size: 16384
# Reuse write buffers across connections to lower heap pressure (default: true).
shared_write_buffer: true
# Close each connection once it reaches this age, forcing OTel Arrow
# streams to rotate so load balancers can redistribute clients evenly
# (default: 5m).
max_connection_age: 5m
| Option | Default | Description |
|---|---|---|
max_recv_msg_size | 64MiB | Maximum message size the server accepts |
read_buffer_size | 64KiB | Per-connection read buffer |
write_buffer_size | 16KiB | Per-connection write buffer |
shared_write_buffer | true | Reuse write buffers across connections |
max_connection_age | 5m | Age at which a connection is closed, bounding OTel Arrow stream lifetime |
max_connection_age is the server-side bound on how long an OTel Arrow stream can live. After a connection reaches this age the server sends a gRPC GOAWAY and, following a one-minute grace period for in-flight requests, closes it. This recycles long-lived Arrow streams so an L4/L7 load balancer can rebalance clients across Uptrace instances and so dictionary state stays bounded. See the OTel Arrow in production experiment for the rationale.
When sending data with the OTel Arrow exporter, keep the client's arrow.max_stream_lifetime below this value so streams recycle gracefully — see Ingesting telemetry using OTel Arrow.
Domain and URL
site:
# Used for dashboard links, CORS, and auth redirects.
# Must match your reverse proxy setup.
url: https://uptrace.mycompany.com
# Optional: dedicated ingestion endpoint.
# Defaults to site.url if not set.
ingest_url: https://ingest.mycompany.com
TLS configuration
Automatic TLS with Let's Encrypt
certmagic:
enabled: true
staging_ca: false # Set true for testing
http_challenge_addr: ':80' # Port for HTTP-01 challenge
Manual TLS certificates
Generate a self-signed certificate for development:
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
-keyout uptrace.key -out uptrace.crt -subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,DNS:uptrace.local"
Add to the system trust store:
sudo cp uptrace.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
Configure Uptrace:
listen:
grpc:
addr: ':4317'
http:
addr: ':443'
tls:
cert_file: /etc/uptrace/tls/uptrace.crt
key_file: /etc/uptrace/tls/uptrace.key
min_version: '1.2'
site:
url: 'https://uptrace.mycompany.com'
Database TLS
Full TLS client options (PostgreSQL example):
pg:
addr: localhost:5432
user: uptrace
password: uptrace
database: uptrace
tls:
cert_file: /etc/uptrace/client.crt
key_file: /etc/uptrace/client.key
ca_file: /etc/uptrace/ca.crt
min_version: '1.2'
max_version: '1.3'
insecure_skip_verify: false
server_name_override: ''
Common shortcuts:
# Use system certificate store
pg:
tls: {}
# Skip certificate verification (testing only)
pg:
tls:
insecure_skip_verify: true
To connect without TLS, remove the tls block. Uptrace refuses a client tls block with insecure: true for pg, ch_cluster replicas, redis_cache, kafka, and self_monitoring. Only mailer.smtp.tls accepts insecure. Without a tls block, the PostgreSQL client uses the sslmode of pg.dsn, for example sslmode=disable, and connects in plaintext when there is no dsn.
Authentication
Seed data
Initial users, organizations, and projects are created when you run uptrace db seed, and can be modified through the UI afterward. Each entry has a key, and other entries refer to it with user_key, org_key, project_key, or org_user_key:
seed_data:
users:
- key: admin_user
name: System Administrator
email: admin@mycompany.com
password: ChangeThisPassword123!
email_confirmed: true
user_tokens:
- key: admin_token
user_key: admin_user
token: secure_admin_token_here
orgs:
- key: main_org
name: My Company
org_users:
- key: admin_org_membership
org_key: main_org
user_key: admin_user
role: owner # owner, admin, member, viewer, billing_manager, collaborator
projects:
- key: production_project
name: Production Environment
org_key: main_org
project_tokens:
- key: prod_token
project_key: production_project
token: prod_telemetry_secret # Used in OTLP DSN
project_users:
- key: admin_project_access
project_key: production_project
org_user_key: admin_org_membership # an org_users key, not a user key
perm_level: admin # none, view, edit, admin
Auth settings
auth:
# Disable all login routes, including SSO
#disabled: true
# Block new password registrations
#sign_up: false
# Block password sign-ins; SSO remains available
#sign_in: false
# Restrict registration to a domain
#email_regexp: '^.+@mycompany\.com$'
| Scenario | Setting |
|---|---|
| Disable all login routes | disabled: true |
| No new registrations | sign_up: false |
| No password sign-ins | sign_in: false |
| Restrict to company domain | email_regexp: '^.+@mycompany\.com$' |
Single Sign-On
Uptrace supports enterprise identity providers:
Processing pipelines
Uptrace processes telemetry through parallel pipelines — one each for spans, span links, logs, events, and metrics. Each pipeline has its own block under pipelines. For detailed tuning guidance, see Scaling Uptrace.
pipelines:
spans:
max_threads: 16 # Processing goroutines (default: CPU cores)
ch_max_insert_size: 10000 # Records per INSERT batch
max_buffered_bytes: 536870912 # 512 MiB buffer cap
span_links:
disabled: false
max_threads: 2
ch_max_insert_size: 5000
max_buffered_bytes: 67108864 # 64 MiB
logs:
max_threads: 12
ch_max_insert_size: 15000
max_buffered_bytes: 402653184 # 384 MiB
events:
max_threads: 4
ch_max_insert_size: 5000
max_buffered_bytes: 134217728 # 128 MiB
metrics:
max_threads: 8
ch_max_insert_size: 10000
max_buffered_bytes: 268435456 # 256 MiB
max_cumulative_timeseries: 2000000 # Cumulative-to-delta conversion limit
Query limits
Prevent resource exhaustion from expensive queries:
trace:
query_limit: 500000 # Max spans per query
max_memory_usage_bytes: 500000000 # 500 MB per query
Redis cache
redis_cache:
addrs:
alpha: redis-1:6379
bravo: redis-2:6379
username: ''
password: 'redis_password'
db: 0
dial_timeout: 5s
read_timeout: 3s
write_timeout: 3s
#tls:
# insecure_skip_verify: false
Features
MCP and OAuth
The MCP server accepts requests at /mcp/<project_id>. Browser sign-in uses the built-in OAuth authorization server. API tokens remain available when browser sign-in is disabled.
mcp:
disabled: false
http_timeout: 30s
defaults:
limit: 100
lookback: 1h
oauth:
disabled: false
access_token_ttl: 1h
refresh_token_ttl: 720h
dcr: open
mcp.disabled turns off the MCP endpoint. mcp.http_timeout limits requests from MCP tools to the Uptrace API. The query defaults set the result limit and time window when a tool call omits them.
oauth.disabled turns off browser sign-in for MCP clients, but API tokens still work. Access tokens expire after access_token_ttl. Refresh tokens expire after refresh_token_ttl, so a client must ask for approval again. dcr: off refuses dynamic client registration; common MCP clients use the default open setting.
Generative model client
The optional genai client runs structured tasks such as incident grouping. Set protocol to enable it, and choose a model. Leave protocol unset to keep these tasks off.
genai:
protocol: openai
api_key: ${GENAI_API_KEY}
model: YOUR_MODEL
timeout: 60s
max_retries: 3
Use openai for the OpenAI API or a server that enforces JSON schemas. Use openai-compat for a JSON-mode server such as Ollama; this protocol requires base_url. Use anthropic for the Anthropic Messages API. api_key can be empty when base_url points to a server without authentication. Run uptrace genai check to test the configured endpoint.
Alerting and service graph
alerting:
#monitors: false # Stop the monitor runners
#notifications: false # Stop delivering alert notifications
#incidents:
# disabled: true # Stop grouping alerts into incidents
pipelines:
service_graph:
#disabled: true # Disable service graph processing
self_monitoring:
disabled: false
dsn: http://project1_secret@uptrace.local/2?grpc=4317
Source maps
Configure JavaScript source map processing to resolve minified stack traces:
sourcemaps:
#disabled: true
#upload: false
#http_timeout: 5s
#source_cache_size: 100000
#consumer_cache_size: 4
#error_cache_size: 100000
| Option | Default | Description |
|---|---|---|
disabled | false | Disable all sourcemap processing |
upload | true | Accept user-uploaded source maps (storage and resolution) |
http_timeout | 5s | Timeout for fetching discovered source maps over HTTP (max 30s) |
source_cache_size | scales with CPU | Max resolved source positions to cache |
consumer_cache_size | scales with CPU | Max parsed source map files in memory |
error_cache_size | scales with CPU | Max failed lookups to cache |
Notifications
Email (SMTP)
mailer:
smtp:
enabled: false
host: localhost
port: 1025
username: mailhog
password: mailhog
from: no-reply@uptrace.local
#tls: { insecure: true }
Gmail example:
- Generate an app-specific password in Gmail settings.
- Configure Uptrace:
mailer:
smtp:
enabled: true
host: smtp.gmail.com
port: 587
username: youraccount@gmail.com
password: your_app_specific_password
from: 'youraccount@gmail.com'
Without a tls block, Uptrace uses STARTTLS when the server offers it. With a tls block, TLS is required: port 465 uses implicit TLS (SMTPS), and any other port uses STARTTLS. tls: { insecure: true } turns TLS off.
Telegram
telegram:
bot_token: 'your_telegram_bot_token'
Setup guide: BotFather.
System settings
Logging
logging:
level: INFO # DEBUG, INFO, WARN, ERROR
Premium license
license:
key: 'your_premium_license_key'
Premium features: ClickHouse distributed tables, advanced SSO, priority support.
Deployment
Production checklist
Security:
- Change all default passwords and tokens in
seed_data - Configure TLS for all connections
- Set up auth restrictions (
auth.email_regexp) - Configure firewall rules
High availability:
- Deploy multiple Uptrace instances behind a load balancer
- Configure PostgreSQL with read replicas
- Set up ClickHouse replication (minimum 3 nodes)
- Configure Redis for caching and session storage
- Set up database backups
Performance:
- Tune processing pipelines based on ingestion volume (see Scaling Uptrace)
- Configure data retention policies
- Set up monitoring for Uptrace itself
Reverse proxy
site:
url: https://uptrace.mycompany.com # Main deployment
# url: https://mycompany.com/uptrace # Subpath deployment
When deploying under a subpath (e.g., /uptrace), the reverse proxy must strip the prefix before forwarding. Rewrite /uptrace(/|$)(.*) to /$2:
location ~ ^/uptrace(/|$) {
rewrite ^/uptrace$ / break;
rewrite ^/uptrace(/.*)$ $1 break;
proxy_pass http://uptrace:14318;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Health check endpoints: GET /health/live for liveness and GET /health/ready for readiness. See health endpoints.
Scaling
For processing pipeline tuning, ClickHouse insert optimization, sharding, and resource sizing, see Scaling Uptrace.