Environment Variables Reference
Temps environment variables fall into two groups: server settings that configure the temps binary itself (TEMPS_*, read when temps serve starts), and application variables that Temps passes to your deployed containers. This page lists both, plus the CLI and SDK variables.
To add, scope and preview-gate your app's variables, see Manage Environment Variables.
Server Configuration
These environment variables configure the Temps server itself:
| Variable | CLI Flag | Default | Description |
|---|---|---|---|
TEMPS_ADDRESS | --address | 127.0.0.1:3000 | HTTP server address and port |
TEMPS_TLS_ADDRESS | --tls-address | (optional) | HTTPS server address and port |
TEMPS_DATA_DIR | --data-dir | ~/.temps | Data directory for keys and configuration |
TEMPS_LOG_LEVEL | --log-level | info | Log level: trace, debug, info, warn, error |
TEMPS_CONSOLE_ADDRESS | --console-address | (optional) | Console listener (public ingest + admin if no split) |
Admin Listener (optional)
When the admin listener is configured, admin/management routes bind to a separate address while TEMPS_CONSOLE_ADDRESS only serves public ingest endpoints (analytics events, error tracking ingest, AI gateway, worker route sync, email tracking pixels). See the admin listener guide for the full route classification and deployment patterns.
| Variable | CLI Flag | Default | Description |
|---|---|---|---|
TEMPS_CONSOLE_ADMIN_ADDRESS | --console-admin-address | (optional) | Dedicated bind for admin/management routes. Unset = single listener mode (backwards-compat) |
TEMPS_ADMIN_ALLOWED_IPS | — | (optional) | Comma-separated IPs/CIDRs allowed to reach the admin listener (e.g. 10.0.0.0/8,127.0.0.1) |
TEMPS_ADMIN_ALLOWED_HOSTS | — | (optional) | Comma-separated Host header values allowed on the admin listener |
TEMPS_ADMIN_TRUST_FORWARDED_FOR | — | false | Honor X-Forwarded-For for the IP gate — only from loopback peers (anti-spoof) |
Example
# Single listener (backwards-compatible default)
export TEMPS_ADDRESS=0.0.0.0:8080
export TEMPS_TLS_ADDRESS=0.0.0.0:8443
export TEMPS_LOG_LEVEL=debug
export TEMPS_DATA_DIR=/var/lib/temps
# Two listeners with admin on loopback + IP allowlist
export TEMPS_CONSOLE_ADDRESS=0.0.0.0:8080
export TEMPS_CONSOLE_ADMIN_ADDRESS=127.0.0.1:8081
export TEMPS_ADMIN_ALLOWED_IPS=127.0.0.1/32,10.0.0.0/8
export TEMPS_ADMIN_ALLOWED_HOSTS=admin.temps.example.com
Database Configuration
| Variable | CLI Flag | Default | Description |
|---|---|---|---|
TEMPS_DATABASE_URL | --database-url | (required) | PostgreSQL connection string |
Always set TEMPS_DATABASE_URL as an environment variable, not a CLI flag.
When you pass the database URL as --database-url=postgres://user:pass@host/db,
the full value — including the password — appears in pgrep -af, ps aux, and
/proc/self/cmdline, visible to any user on the server who can list processes.
Setting it as an environment variable keeps the credential out of the process
table entirely. The --database-url flag still works for backwards compatibility,
and Temps will scrub it from its own argv after startup, but the env var approach
is more robust across all OS and tooling.
Database URL Format
postgresql://[user[:password]@][host][:port][/database][?param1=value1&...]
Example
# Preferred: set as environment variable (never visible in process listings)
export TEMPS_DATABASE_URL=postgresql://temps:password@localhost:5432/temps
temps serve
# Avoid: flag form exposes the password in ps/pgrep output
# temps serve --database-url=postgresql://temps:password@localhost:5432/temps
Connection Pool Tuning
Control the PostgreSQL connection pool size and timeouts:
| Variable | Default | Description |
|---|---|---|
TEMPS_DB_MAX_CONNECTIONS | 100 | Maximum connections in the pool |
TEMPS_DB_MIN_CONNECTIONS | 5 | Minimum idle connections kept open |
TEMPS_DB_ACQUIRE_TIMEOUT | 30 | Seconds to wait for a connection |
TEMPS_DB_IDLE_TIMEOUT | 600 | Seconds before idle connections are closed |
For small servers (2GB RAM), reduce TEMPS_DB_MAX_CONNECTIONS to 20-30. If you see slow_acquire_threshold warnings in logs, it means the pool is saturated — either increase the max or investigate long-running queries.
# Example: tuning for a small VPS
export TEMPS_DB_MAX_CONNECTIONS=30
export TEMPS_DB_MIN_CONNECTIONS=2
export TEMPS_DB_IDLE_TIMEOUT=300
Data Directory
Temps stores sensitive data in the data directory (~/.temps by default):
~/.temps/
├── encryption_key # Master key for AES-256-GCM encryption at rest (auto-generated)
└── auth_secret # Session authentication secret (auto-generated)
Application environment variable values and managed-service credentials are encrypted at rest with AES-256-GCM under this one master key. Back up ~/.temps/encryption_key and ~/.temps/auth_secret. Losing these files means you cannot decrypt your existing data.
ClickHouse Analytics Backend
By default Temps stores analytics events, traces, metrics and proxy logs in PostgreSQL/TimescaleDB, with no extra configuration. For large workloads you can move those four domains to ClickHouse by setting the TEMPS_CLICKHOUSE_* variables and restarting temps serve, which reads them at startup. There is no rebuild and no cargo feature flag: the ClickHouse backends are compiled in and stay dormant until configured. The step-by-step procedure, including backfill, is in Migrate to ClickHouse.
| Variable | Required | Default | Description |
|---|---|---|---|
TEMPS_CLICKHOUSE_URL | Yes | — | ClickHouse HTTP endpoint URL |
TEMPS_CLICKHOUSE_USER | Yes | — | ClickHouse username |
TEMPS_CLICKHOUSE_PASSWORD | Yes | — | ClickHouse password |
TEMPS_CLICKHOUSE_DATABASE | No | temps (when the URL is set) | ClickHouse database name |
Fail-closed activation
ClickHouse turns on only when the URL, user and password are all set and non-empty (the database name defaults to temps once the URL is set). Partial or empty configuration is treated as off, and Temps stays on PostgreSQL/TimescaleDB. A variable that is set but empty counts as unset, so a half-configured server never silently loses data.
# Enable the ClickHouse backends, then restart temps serve
export TEMPS_CLICKHOUSE_URL=http://clickhouse:8123
export TEMPS_CLICKHOUSE_USER=temps
export TEMPS_CLICKHOUSE_PASSWORD=your-clickhouse-password
# Optional; defaults to "temps"
export TEMPS_CLICKHOUSE_DATABASE=temps
The same variables enable all four domains in one database: analytics events, traces, resource metrics and proxy logs. Traces, metrics and proxy logs switch backend (new writes go to ClickHouse). Analytics events work differently, as described below.
Analytics events: dual write
When ClickHouse is enabled, the analytics-events plugin:
- Applies the embedded ClickHouse schema migrations —
events,events_5m_mv, andsessions, tracked in a_temps_ch_migrationstable. - Spawns the
ChFanoutWorkeron the tokio runtime. - Swaps the read-side analytics events service to
ClickHouseEventsBackend.
Migrations and the worker run on background tasks so plugin init does not block on remote calls. If migrations fail, queries surface the error per-call rather than crashing startup.
PostgreSQL stays the system of record for events
PostgreSQL/TimescaleDB remains the source of truth. record_event writes the event to PostgreSQL synchronously, then enqueues the event id into an events_ch_outbox table (INSERT ... ON CONFLICT (event_id) DO NOTHING). The worker drains that outbox asynchronously, claiming batches with FOR UPDATE SKIP LOCKED and inserting into ClickHouse.
This makes ingestion resilient:
- The outbox enqueue is best-effort. If it fails, the event is still recorded in PostgreSQL (the failure is logged at debug); that single event simply won't replicate to ClickHouse.
- A ClickHouse outage never blocks ingestion. The write path never waits on ClickHouse — rows queue in the outbox and are retried on later poll cycles.
- Retries are safe. The ClickHouse
eventstable usesReplacingMergeTree(_version)and dedupes over its sort key (withevent_idas the most granular component), so re-delivering the same event collapses to one row.
The worker also runs an hourly retention sweep that deletes delivered outbox rows older than 7 days, and a 5-minute dead-letter scan that warn-logs the count of rows that hit the retry ceiling (attempts >= max_attempts, default 10) without deleting them.
Analytics behavior differences from the PostgreSQL backend
A few analytics behaviors differ by design when events are read from ClickHouse:
- Unique counts are approximate. The ClickHouse backend uses
uniq()(HyperLogLog), accurate to within ~1% at scale, instead of the exactCOUNT(DISTINCT)used by PostgreSQL. - The self-referral filter is PostgreSQL-only. The referrer-hostname self-referral filter checks the
project_custom_domainstable, which is not replicated to ClickHouse.
Geolocation (country/region/city) is denormalized onto each ClickHouse event row at fan-out time, so breakdowns and timelines group on plain ClickHouse columns without a cross-database join.
PostgreSQL remains the system of record for analytics events and for all platform data (deployments, domains, users, configuration). To disable ClickHouse, unset the TEMPS_CLICKHOUSE_* variables and restart temps serve. See Migrate to ClickHouse for the enable, verify and rollback flow.
Application Environment Variables
These are environment variables you configure for your deployed applications:
Setting Environment Variables
Set an application environment variable
- 1
Navigate to Project then Environment then Settings.
- 2
Go to the Environment Variables section.
- 3
Add or edit the variable, entering the key (e.g. DATABASE_URL) and its value.
Checkpoint: Confirm the new variable appears in the Environment Variables list for the chosen environment.
Environment variables are set per project and scoped to environments. Values are encrypted at rest and applied on the next deployment.
Via Dashboard:
- Navigate to Project → Environment → Settings
- Go to Environment Variables section
- Add or edit variables
Via CLI:
# Set for several environments at once
bunx @temps-sdk/cli environments vars set \
--environments production,staging \
DATABASE_URL "postgresql://user:pass@host/db"
# Set for one environment
bunx @temps-sdk/cli environments vars set \
--environments production \
DATABASE_URL "postgresql://user:pass@host/db"
Without --environments, the CLI asks which environments to use. The commands act on the project linked to the current directory or your default project; pass --project <slug> to environments vars to pick another.
Via API:
await fetch(`https://your-temps-instance.com/api/projects/${projectId}/env-vars`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
key: "DATABASE_URL",
value: "postgresql://user:pass@host/db",
environment_ids: [1],
}),
});
The full API (list, update, delete, secrets, preview control) is in Manage Environment Variables.
Variables Temps injects
Temps also sets variables in every container it deploys: HOST, PORT (in v0.1.0-beta.56, not on rollbacks or promotions), TEMPS_API_URL, TEMPS_API_TOKEN, CRON_SECRET, TEMPS_NODE_NAME, TEMPS_NODE_ID and TEMPS_REPLICA, plus credentials for linked services and error-tracking and OpenTelemetry settings. The full table, with values and version notes, is in Manage Environment Variables.
Framework-Specific Variables
Common environment variables for popular frameworks:
Next.js:
NODE_ENV=production
NEXT_PUBLIC_API_URL=https://api.example.com
React/Vite:
VITE_API_URL=https://api.example.com
Node.js:
NODE_ENV=production
Don't set PORT yourself: Temps sets it to the port it routes traffic to and replaces your value. Change the port in the project or environment settings instead.
Python:
PYTHONUNBUFFERED=1
FLASK_ENV=production
CLI Configuration
These environment variables configure the Temps CLI:
| Variable | Description |
|---|---|
TEMPS_API_URL | API endpoint URL (e.g., https://your-temps-instance.com) |
TEMPS_API_TOKEN | API authentication token |
TEMPS_API_KEY | API key (alternative to token) |
NO_COLOR | Disable colored output (set to 1 or true) |
Example
export TEMPS_API_URL=https://your-temps-instance.com
export TEMPS_API_TOKEN=your-token-here
Configuration Files
CLI configuration is stored in:
- Config file:
~/.temps/config.json - Credentials: stored securely under
~/.temps/with mode0600, managed byloginandlogout
Use bunx @temps-sdk/cli configure show to view current configuration.
SDK Configuration
Node.js SDK
| Variable | Description |
|---|---|
TEMPS_API_URL | Your Temps API URL |
TEMPS_TOKEN | Your API key or deployment token |
TEMPS_PROJECT_ID | Project ID (optional, can be set in code) |
React Analytics SDK
| Variable | Description |
|---|---|
NEXT_PUBLIC_TEMPS_API_URL | Temps API URL (for Next.js) |
NEXT_PUBLIC_TEMPS_PROJECT_ID | Project ID (for Next.js) |
Example
# Node.js SDK
export TEMPS_API_URL=https://your-temps-instance.com
export TEMPS_TOKEN=your-token-here
# Next.js with React Analytics
export NEXT_PUBLIC_TEMPS_API_URL=https://your-temps-instance.com
export NEXT_PUBLIC_TEMPS_PROJECT_ID=123
Precedence Rules
A variable belongs to the project and is assigned to one or more environments. There are no separate project-level and environment-level copies to merge: a key has one value per environment, and creating a key that already exists in one of the selected environments is rejected.
At deploy time, Temps builds the container's variables in this order. A later step replaces an earlier value with the same name:
HOST=0.0.0.0, a default you can override- Your variables assigned to the target environment
- Variables from linked managed services (
POSTGRES_URL,REDIS_URLand so on) - Variables Temps owns:
SENTRY_DSN,TEMPS_API_URL,TEMPS_API_TOKEN,CRON_SECRETand theOTEL_*settings, thenPORT,TEMPS_NODE_NAME,TEMPS_NODE_IDandTEMPS_REPLICA
In v0.1.0-beta.56, a variable you define with the same name as a linked-service variable is replaced by the service's value. Nightly builds since 2026-08-30 reverse steps 2 and 3, so your own value wins. Variables on the host running temps serve are never passed to app containers.
Give one environment its own value
Give one environment its own value
- 1
Open the project and go to Environment Variables.
- 2
If API_URL is already assigned to production, edit it and remove production from its environments.
- 3
Add API_URL again with the production value, assigned to production only.
Checkpoint: Confirm the list shows one API_URL per environment, each with its own value.
To use different values per environment, create one variable per value and assign each to different environments:
# Staging value
bunx @temps-sdk/cli environments vars set \
--environments staging \
API_URL "https://api-staging.example.com"
# Production value
bunx @temps-sdk/cli environments vars set \
--environments production \
API_URL "https://api-prod.example.com"
To change the value of an existing variable, run the same command with --update and without --environments; the variable keeps its current environments.
Project variables
In this section, a Project is a group of Services; elsewhere on this page, "project" still means a single deployable app, which the experimental feature calls a Service.
This layer is experimental and in nightly builds only; it does not exist in a beta or stable release yet. See Projects and Services.
When a Service belongs to a Project, the Project's shared variables become one more layer. For a deployment of the Service, from highest to lowest priority:
- Values Temps sets for the platform, such as
SENTRY_DSN,TEMPS_API_URL,TEMPS_API_TOKENandCRON_SECRET. A Project variable cannot replace them.HOSTis the exception: a Service or Project variable can set it. - The Service's own variables (the environment-level and project-level values above). Where a Service variable and a Project variable with the same name both apply to the environment, the Service's value wins.
- The Project's shared variables. Within the Project, a variable scoped to the environment's slug (for example
production) wins over the Project's all-environments variable with the same name. - Defaults from linked databases and storage, such as
DATABASE_URLfrom a linked PostgreSQL. A Project variable overrides them.
All-environments Project variables reach preview environments only when marked to include previews (off by default). Secret Project variables are write-only, and changes apply on each Service's next deployment.
Best Practices
Security
- Never commit secrets: Use environment variables for sensitive data
- Use different values per environment: Production should have different credentials than staging
- Rotate secrets regularly: Update API keys and tokens periodically
- Use secure storage: Values are encrypted at rest, but anyone with dashboard access to the project can read them. External secret stores (Vault, AWS Secrets Manager, Infisical) are a Premium feature; see Premium
Organization
- Use descriptive names:
DATABASE_URLis better thanDB - Document variables: Keep a list of required variables in your README
- Group related variables: Use prefixes like
DATABASE_,API_,REDIS_ - Set defaults when possible: Provide sensible defaults in your application code
Debugging
- Check variable precedence: Verify which value is actually being used
- Use logging: Log variable names (not values) to verify they're set
- Test locally: Use
.envfiles for local development - Verify in dashboard: Check environment variables in the Temps dashboard