This guide covers using environment variables to configure the ToolHive Registry Server. Environment variables provide a flexible way to override configuration values without modifying YAML files, making them ideal for container deployments, CI/CD pipelines, and environment-specific configurations.
The ToolHive Registry Server uses Viper for configuration management, which supports loading configuration from multiple sources with a clear precedence order.
Configuration values are resolved in this order (lowest to highest priority):
- Default values - Hardcoded defaults in the application
- Configuration file - Values from the YAML config file
- Environment variables - Values from
THV_REGISTRY_*environment variables - Command-line flags - Values from CLI flags (e.g.,
--address)
Higher priority sources override lower ones. For example, if database.host is set to localhost in the YAML file but THV_REGISTRY_DATABASE_HOST=postgres.example.com is set, the environment variable value (postgres.example.com) will be used.
All environment variables use the THV_REGISTRY_ prefix (ToolHive Registry) to avoid conflicts with other applications.
- Prefix: All variables start with
THV_REGISTRY_ - Nested keys: Use underscores (
_) to represent nested configuration - Case: Environment variables are case-insensitive (but uppercase is conventional)
- Dots to underscores: Configuration key
database.hostbecomesTHV_REGISTRY_DATABASE_HOST
| Configuration Key | Environment Variable | Example Value |
|---|---|---|
registryName |
THV_REGISTRY_REGISTRYNAME |
production-registry |
database.host |
THV_REGISTRY_DATABASE_HOST |
postgres.example.com |
database.port |
THV_REGISTRY_DATABASE_PORT |
5432 |
auth.mode |
THV_REGISTRY_AUTH_MODE |
oauth |
auth.oauth.realm |
THV_REGISTRY_AUTH_OAUTH_REALM |
mcp-registry |
# Change the listening address (default: :8080)
export THV_REGISTRY_ADDRESS=:9090
# Set the registry name
export THV_REGISTRY_REGISTRYNAME=production-registry# Database connection settings
export THV_REGISTRY_DATABASE_HOST=postgres.example.com
export THV_REGISTRY_DATABASE_PORT=5432
export THV_REGISTRY_DATABASE_USER=registry_app
export THV_REGISTRY_DATABASE_DATABASE=registry_prod
export THV_REGISTRY_DATABASE_SSLMODE=verify-full
export THV_REGISTRY_DATABASE_MIGRATIONUSER=registry_migrator
# Connection pool settings
export THV_REGISTRY_DATABASE_MAXOPENCONNS=25
export THV_REGISTRY_DATABASE_MAXIDLECONNS=5
export THV_REGISTRY_DATABASE_CONNMAXLIFETIME=1hNote: Database passwords are managed via PostgreSQL's .pgpass file or the PGPASSFILE environment variable, not through THV_REGISTRY_* variables.
# Set authentication mode
export THV_REGISTRY_AUTH_MODE=oauth # or "anonymous" for development
# OAuth/OIDC configuration
export THV_REGISTRY_AUTH_OAUTH_RESOURCEURL=https://registry.example.com
export THV_REGISTRY_AUTH_OAUTH_REALM=mcp-registryNote: OAuth provider configuration (including issuer URLs, audiences, and client secrets) should be specified in the YAML configuration file for security and complexity reasons.
# Set log level (debug, info, warn, error)
export THV_REGISTRY_LOG_LEVEL=debug
# Or use the unprefixed version (backward compatible)
export LOG_LEVEL=debugEnvironment variables integrate seamlessly with Docker and Docker Compose:
docker run \
-e THV_REGISTRY_DATABASE_HOST=postgres \
-e THV_REGISTRY_DATABASE_PORT=5432 \
-e THV_REGISTRY_AUTH_MODE=anonymous \
-v $(pwd)/config.yaml:/config.yaml \
toolhive-registry-api serve --config /config.yamlversion: '3.8'
services:
registry:
image: toolhive-registry-api
environment:
THV_REGISTRY_DATABASE_HOST: postgres
THV_REGISTRY_DATABASE_PORT: 5432
THV_REGISTRY_DATABASE_USER: registry_app
THV_REGISTRY_DATABASE_DATABASE: registry
THV_REGISTRY_AUTH_MODE: anonymous
THV_REGISTRY_LOG_LEVEL: info
volumes:
- ./config.yaml:/config.yaml
command: serve --config /config.yamlEnvironment variables work well with Kubernetes ConfigMaps and Secrets:
apiVersion: v1
kind: ConfigMap
metadata:
name: registry-config
data:
THV_REGISTRY_DATABASE_HOST: "postgres-service"
THV_REGISTRY_DATABASE_PORT: "5432"
THV_REGISTRY_AUTH_MODE: "oauth"
THV_REGISTRY_LOG_LEVEL: "info"apiVersion: apps/v1
kind: Deployment
metadata:
name: registry-server
spec:
template:
spec:
containers:
- name: registry
image: toolhive-registry-api
envFrom:
- configMapRef:
name: registry-config
volumeMounts:
- name: config
mountPath: /config.yaml
subPath: config.yaml
volumes:
- name: config
configMap:
name: registry-yaml-configEnvironment variables have limited support for complex nested arrays and structures. The following configurations should be defined in the YAML file:
registries[]- Registry configurations (multiple registries with nested settings)registries[].syncPolicy- Sync policy per registryregistries[].filter- Filter rules per registryauth.oauth.providers[]- OAuth provider configurations
Why? These structures involve arrays of objects with multiple nested fields, which don't map cleanly to environment variables.
- Use YAML for complex structures: Define registries, OAuth providers, and filter rules in the YAML configuration file
- Use environment variables for overrides: Override simple values like database host, authentication mode, or log level
- Use command-line flags sparingly: Reserve flags for runtime overrides (e.g.,
--addressfor port changes)
- Secrets in YAML files: For sensitive values like OAuth client secrets, use file references (e.g.,
clientSecretFile) rather than inline values - Environment variables in logs: Be careful not to log environment variables that might contain sensitive information
- Kubernetes Secrets: For Kubernetes deployments, use Secret objects for sensitive environment variables:
apiVersion: v1
kind: Secret
metadata:
name: registry-secrets
type: Opaque
stringData:
THV_REGISTRY_AUTH_MODE: "oauth"
---
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: registry
envFrom:
- secretRef:
name: registry-secretsOverride auth mode for local testing:
# Start with anonymous auth for development
THV_REGISTRY_AUTH_MODE=anonymous ./thv-registry-api serve --config config-dev.yamlOverride database and logging for integration tests:
export THV_REGISTRY_DATABASE_HOST=localhost
export THV_REGISTRY_DATABASE_PORT=5432
export THV_REGISTRY_DATABASE_USER=test_user
export THV_REGISTRY_DATABASE_DATABASE=test_registry
export THV_REGISTRY_AUTH_MODE=anonymous
export THV_REGISTRY_LOG_LEVEL=debug
./thv-registry-api serve --config config-test.yamlMinimal environment overrides with production config:
# Production uses YAML for most config, only override deployment-specific values
export THV_REGISTRY_DATABASE_HOST=postgres-primary.prod.svc.cluster.local
export THV_REGISTRY_LOG_LEVEL=info
./thv-registry-api serve --config config-production.yamlTo understand which configuration source is being used:
- Enable debug logging:
THV_REGISTRY_LOG_LEVEL=debug - Check server startup logs for configuration values
- Verify environment variables are set:
env | grep THV_REGISTRY_
Environment variable not taking effect:
- Check the variable name matches the configuration key (use underscores, not dots)
- Verify the
THV_REGISTRY_prefix is present - Ensure the variable is exported:
export THV_REGISTRY_DATABASE_HOST=... - Remember: YAML values are loaded first, then overridden by env vars
Configuration validation errors:
- Environment variables are type-coerced by Viper (strings to integers, etc.)
- Invalid values will fail validation after unmarshaling
- Check the error message for the specific configuration key that failed
For a complete list of all configuration options, see:
- Configuration Reference - Complete YAML configuration options
- Database Setup - Database configuration and credentials
- Authentication - OAuth/OIDC setup
For the underlying technology:
- Viper Documentation - Configuration library used by ToolHive