PostgreSQL
Windshift supports PostgreSQL as an alternative to SQLite for teams that need higher write concurrency or integration with existing database infrastructure.
Connection String
Pass a PostgreSQL connection string via CLI flag or environment variable:
# CLI flag
./windshift --postgres-connection-string "postgres://user:password@localhost:5432/windshift?sslmode=disable"
# Short flag
./windshift --pg-conn "postgres://user:password@localhost:5432/windshift?sslmode=disable"
# Environment variable
export POSTGRES_CONNECTION_STRING="postgres://user:password@localhost:5432/windshift?sslmode=disable"
./windshiftWhen a PostgreSQL connection string is provided, Windshift ignores the --db flag and uses PostgreSQL instead of SQLite.
Connection Pool
The PostgreSQL pool is bounded so a busy instance, or a burst of agent traffic, cannot exhaust the database with "too many clients already". It is sized from MAX_READ_CONNS:
| Setting | Default | Source |
|---|---|---|
| Max open connections | 30 | MAX_READ_CONNS |
| Max idle connections | 15 | half of MAX_READ_CONNS |
Idle connections are recycled on a lifetime and idle timeout. To raise the ceiling, increase MAX_READ_CONNS (--max-read-conns), but keep it well under the PostgreSQL server's own max_connections, and leave headroom for other clients and for any runner or sidecar processes.
Per-user concurrency
Independently of the pool, MAX_USER_CONCURRENCY (default 16) caps how many /api requests a single authenticated user, or agent, can have in flight at once. This keeps one heavy client from monopolising the pool. Set it to 0 to disable the cap.
The pool is managed by Go's database/sql package.
Docker Compose Setup
services:
windshift:
image: ghcr.io/windshiftapp/windshift:latest
restart: unless-stopped
ports:
- "8080:8080"
environment:
- BASE_URL=https://windshift.example.com
- SSO_SECRET=${SSO_SECRET}
- POSTGRES_CONNECTION_STRING=postgres://windshift:${POSTGRES_PASSWORD}@postgres:5432/windshift?sslmode=disable
- ATTACHMENT_PATH=/data/attachments
volumes:
- windshift-data:/data
depends_on:
postgres:
condition: service_healthy
postgres:
image: postgres:17-alpine
restart: unless-stopped
environment:
- POSTGRES_USER=windshift
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=windshift
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U windshift"]
interval: 5s
timeout: 5s
retries: 5
volumes:
windshift-data:
postgres-data:Schema Management
Windshift manages database schemas automatically. On startup it runs embedded migration files for all tables (items, users, tests, workflows, portal, notifications, permissions, etc.). SQL placeholders are automatically converted between SQLite (?) and PostgreSQL ($1, $2, ...) syntax.
No manual schema setup or migration commands are required.
SSL/TLS
For production PostgreSQL connections, use sslmode in the connection string:
# Require SSL
--pg-conn "postgres://user:pass@db.example.com:5432/windshift?sslmode=require"
# Verify server certificate
--pg-conn "postgres://user:pass@db.example.com:5432/windshift?sslmode=verify-full&sslrootcert=/path/to/ca.pem"Backups
Use standard PostgreSQL backup tools:
# Logical backup
pg_dump -U windshift windshift > backup.sql
# Compressed backup
pg_dump -U windshift -Fc windshift > backup.dump
# Restore
pg_restore -U windshift -d windshift backup.dumpMigrating from SQLite
To migrate an existing SQLite database to PostgreSQL:
- Set up a fresh PostgreSQL database
- Start Windshift with the PostgreSQL connection string - it will create all tables
- Export data from SQLite and import into PostgreSQL using standard tooling
There is no built-in migration command at this time.