Skip to content

Configuration

Pillow’s services are configured primarily through YAML config files and environment variable overrides. This page covers the configuration for each component.

Mill reads its config from a YAML file. For local development, this is mill/config/config-local.yaml. All values can be overridden via environment variables prefixed with MILL_ (e.g. MILL_DATABASE_POSTGRES_HOST).

mill/config/config-local.yaml
database:
postgres:
host: "localhost"
port: 5432
user: "pillow"
password: "pillow"
database: "pillow"
ssl_mode: "disable"
max_open_conns: 25
max_idle_conns: 10
conn_max_lifetime: "5m"
query_timeout: "30s"

For production, set credentials via environment variables:

Terminal window
MILL_DATABASE_POSTGRES_HOST=your-db-host
MILL_DATABASE_POSTGRES_PORT=5432
MILL_DATABASE_POSTGRES_USER=your_user
MILL_DATABASE_POSTGRES_PASSWORD=your_password
MILL_DATABASE_POSTGRES_DATABASE=pillow
MILL_DATABASE_POSTGRES_SSL_MODE=require
redis:
host: "localhost"
port: 6379
password: ""
db: 0
pool_size: 10
min_idle_conns: 5
max_retries: 3

Kafka is used for the enrichment pipeline and property ingestion events.

kafka:
brokers:
- "localhost:19092"
consumer_group: "mill-ingestion"
topics:
property_ingestion: "property-ingestion"
property_enrichment: "property-enrichment"
property_updates: "property-updates"

Set kafka.disabled: true to run Mill without Kafka.

server:
host: "0.0.0.0"
port: 4000
mode: "debug" # "debug" or "release"
read_timeout: "30s"
write_timeout: "30s"
idle_timeout: "60s"
auth:
jwt_secret: "change-this-in-production"
jwt_expiry: "1h"
refresh_expiry: "24h"
issuer: "mill-analytics"
logging:
level: "debug" # debug, info, warn, error
format: "console" # console or json
output: "stdout"

For enhanced address parsing, configure the libpostal integration:

libpostal:
remote_url: "http://localhost:4400"
timeout: "30s"
max_retries: 3

The Next.js frontend reads from pillow-app/.env.local:

pillow-app/.env.local
NEXT_PUBLIC_MILL_API=http://localhost:4000
MILL_API=http://localhost:4000
MILL_API_TIMEOUT=10000
# Optional: Mapbox for interactive maps
NEXT_PUBLIC_MAPBOX_TOKEN=your-mapbox-token

Local infrastructure is managed via Docker Compose. The development stack includes PostgreSQL (with PostGIS), Redis, and Redpanda:

Terminal window
# Start all infrastructure
docker compose -f docker-compose.dev.yml up -d
# Stop infrastructure
docker compose -f docker-compose.dev.yml down
# View logs
docker compose -f docker-compose.dev.yml logs -f postgres

The Mill also provides a smaller compose file for integration tests:

Terminal window
cd mill
make docker-compose-up # Start Redis + PostgreSQL
make docker-compose-down # Stop and clean volumes

The default config-local.yaml is tuned for local development:

  • Debug logging enabled
  • Rate limiting disabled
  • Sample data loaded on startup
  • Deduplication disabled

For production, use a dedicated config file or override via environment variables:

  • Set MILL_SERVER_MODE=release
  • Set MILL_LOGGING_LEVEL=info and MILL_LOGGING_FORMAT=json
  • Enable rate limiting
  • Use strong JWT secrets
  • Enable SSL for PostgreSQL (ssl_mode: require)

Verify the system is configured correctly:

Terminal window
# Mill API health
curl http://localhost:4000/health
# PostgreSQL connectivity
psql -h localhost -U pillow -d pillow -c "SELECT 1"
# Redis connectivity
redis-cli ping
# Infrastructure status
docker compose -f docker-compose.dev.yml ps

PostgreSQL is provisioned automatically by Docker Compose. Mill auto-migrates the schema on startup. For a manual reset:

Terminal window
# Connect to PostgreSQL
psql -h localhost -U pillow -d pillow
# Apply schema manually (if needed)
psql -h localhost -U pillow -d pillow < mill/scripts/create_comprehensive_properties_table.sql
  • Never commit secrets or credentials to version control
  • Use environment variables for sensitive values in production
  • Rotate JWT secrets regularly
  • Enable SSL/TLS for all production database connections
  • Use Kubernetes Secrets or a secrets manager for production deployments