Getting started
Installation
Run StreamQL as a container, on Kubernetes, with Helm, or as a systemd service.
Requirements#
- A PostgreSQL server, version 13 through 19. It can be self-managed or a managed service.
- A role StreamQL can log in with. Its credentials are given as the upstream URL.
- For slow-query insights, a monitoring role with
pg_read_all_statsandpg_stat_statementsinshared_preload_libraries.
Choose an edition#
StreamQL comes in two editions. They share the same pooling engine, so you can start with one and move to the other.
| Full featured (default) | Pool only | |
|---|---|---|
| What it is | The default binary and image | Pooling without the web UI |
| Web console | yes | no |
Admin API, /metrics, /livez, /readyz | yes | no (the admin port is not bound) |
| Alerts, query insights, MCP access, fleet | yes | no |
| Pooling modes, session-state safety, prepared statements | yes | yes |
Client TLS, upstream TLS, SCRAM, MD5, auth_query | yes | yes |
Limits, queue deadlines, reserve pools, hot reload by SIGHUP | yes | yes |
Run the full edition#
The default build and the image ghcr.io/streamql/streamql include everything: the console and admin API on the admin port (9930), alerts, slow-query insights and the fleet control plane.
docker run --rm -p 6432:6432 -p 127.0.0.1:9930:9930 \
-e STREAMQL_UPSTREAM__URL='postgres://app:APP_PASSWORD@db.example.com:5432/app?sslmode=require' \
ghcr.io/streamql/streamql:latestRun pool only#
Pool only is for places where you want just a pooler: no web UI, no admin listener and no insights pass. There are two ways to get it.
1. Switch it off at run time on the normal binary or image. With admin.enabled = false (or --no-admin) the admin port is not bound at all, so the console, the admin API and /metrics are gone. insights.enabled = false stops the statement fingerprint pass.
STREAMQL_UPSTREAM__URL=file:/run/secrets/upstream_url
STREAMQL_ADMIN__ENABLED=false
STREAMQL_INSIGHTS__ENABLED=false[upstream]
url = "file:/run/secrets/upstream_url"
[admin]
enabled = false
[insights]
enabled = false
[defaults]
mode = "transaction"
max_size = 20# binary
streamql --upstream postgres://app:APP_PASSWORD@db.example.com:5432/app --listen 0.0.0.0:6432 --no-admin
# container, same image as the full edition
docker run --rm -p 6432:6432 \
-e STREAMQL_UPSTREAM__URL='postgres://app:APP_PASSWORD@db.example.com:5432/app?sslmode=require' \
-e STREAMQL_ADMIN__ENABLED=false -e STREAMQL_INSIGHTS__ENABLED=false \
ghcr.io/streamql/streamql:latest2. Use the pool-only build, which does not compile the web console in. It is built without the default features:
cargo build --release -p streamql --no-default-features --features mimalloc # same as: make build-pool-only
docker build --build-arg CARGO_FEATURES="--no-default-features --features mimalloc" -t streamql:pool-only . # same as: make image-pool-onlydocker run --rm -p 6432:6432 \
-e STREAMQL_UPSTREAM__URL='postgres://app:APP_PASSWORD@db.example.com:5432/app?sslmode=require' \
-e STREAMQL_ADMIN__ENABLED=false \
ghcr.io/streamql/streamql:latest-pool-onlyThe published pool-only image and archives are built this way. --no-default-features also leaves out the default secrets-vault feature, so Vault secret references are unavailable in that build. Add it back with --features mimalloc,secrets-vault if you need them.
What you give up in pool only#
- The web console, the admin API under
/api/v1, and the probes and metrics served by the admin listener:/livez,/readyzand/metrics. Use a TCP check on port 6432 for health checks instead ofstreamql probeagainst/readyz. - Alerts, slow-query insights, MCP access and the fleet management views.
- Decision and trace evidence has nothing to read it with; you can switch recording off with
STREAMQL_DATAPLANE__EVIDENCE=false.
What stays#
- All three pooling modes, prepared statements across pooled backends, session-state tracking and replay, pinning, queue deadlines, limits, reserve pools and per-tenant shares.
- Client TLS and upstream TLS, SCRAM-SHA-256, MD5 and
auth_query. - Configuration from a file, environment variables and flags, validation with
streamql config validate, and reload bySIGHUP. - Graceful drain on
SIGTERM, and in-place binary upgrade with--upgrade.
Download a release#
The latest release is read from GitHub in your browser. Pick an edition to see the archives, packages and install commands for your platform. There is no Windows build: StreamQL targets Unix systems.
There is no packaged release to download yet. Build StreamQL from source, or watch the releases page.
git clone https://github.com/streamql/streamql
cd streamql
cargo build --release -p streamql # full featured
cargo build --release -p streamql --no-default-features --features mimalloc # pool onlyRelease assets follow one naming scheme: streamql-<version>-<target>.tar.gz for the full edition, streamql-pool-only-<version>-<target>.tar.gz for pool only (Linux), streamql_<version>-1_<arch>.deb and streamql-<version>-1.<arch>.rpm, plus SHA256SUMS and a .sha256 file next to each download. Container images are ghcr.io/streamql/streamql:<version> and :<version>-pool-only, and latest and latest-pool-only follow the newest stable release. The version has no leading v: tag v0.1.0 is version 0.1.0.
Docker and Docker Compose#
deploy/docker/compose.yaml runs the gateway in front of your database. The image listens on port 6432 for PostgreSQL clients and on port 9930 for the console and API. It runs read-only with all capabilities dropped, and its health check is streamql probe http://127.0.0.1:9930/readyz.
cd deploy/docker
mkdir -p secrets
printf 'postgres://app:APP_PASSWORD@db.example.com:5432/app?sslmode=require' > secrets/upstream_url
openssl rand -hex 24 > secrets/admin_token
docker compose up -dBring your own PostgreSQL#
- Point
upstream_urlat any PostgreSQL 13 through 19 server. Usesslmode=verify-fulland setSTREAMQL_UPSTREAM__SSLROOTCERT(mount the CA file) for a server with a private CA. - A server on the Docker host is
host.docker.internalon Docker Desktop and OrbStack. On Linux addextra_hosts: ["host.docker.internal:host-gateway"]to the service. - Without a server at hand,
docker compose --profile demo up -dalso starts a local PostgreSQL. Createsecrets/postgres_passwordfirst.
Useful settings#
Every setting is an environment variable named STREAMQL_<SECTION>__<KEY>. Put them under environment: or in a .env file next to compose.yaml. A value written as file:/path is read from that file.
| Setting | Default | Meaning |
|---|---|---|
STREAMQL_DEFAULTS__MAX_SIZE | 20 | Server connections per database and role |
STREAMQL_LIMITS__MAX_MESSAGE_BYTES | 268435456 | Largest message held whole in memory |
STREAMQL_LIMITS__STREAM_LARGE_MESSAGES | true | Relay oversized row and COPY data in pieces |
STREAMQL_UPSTREAM__READINESS_GRACE_S | 5 | How long the upstream may be unreachable before /readyz fails |
STREAMQL_ACCESS__TRUSTED_PROXIES | none | CIDR list of reverse proxies whose X-Forwarded-For is believed |
STREAMQL_MCP__ALLOWED_HOSTS | loopback and the public console host | Accepted Host values of /mcp |
Kubernetes with kustomize#
deploy/k8s contains a namespace, a StreamQL deployment and a demo PostgreSQL. Settings live in a generated ConfigMap, so editing a value changes the ConfigMap name and the pods roll.
kubectl apply -k deploy/k8sThe kustomization includes postgres.yaml, a demo database. Remove it from resources and set the upstream URL when you use your own server.
Helm#
The chart is in deploy/helm/streamql. By default it installs one gateway. Credentials can be passed as values or, better, read from existing Secrets.
helm install streamql deploy/helm/streamql \
--namespace streamql --create-namespace \
--set gateway.upstream.url='postgres://app:APP_PASSWORD@db.example.com:5432/app' \
--set gateway.admin.token="$(openssl rand -hex 24)"| Value | Default | Meaning |
|---|---|---|
gateway.replicaCount | 1 | Number of gateway pods |
gateway.image.repository | ghcr.io/streamql/streamql | Image; the tag defaults to the chart appVersion |
gateway.upstream.url / existingSecret / existingSecretKey | empty / empty / url | Upstream URL, or a Secret that holds it |
gateway.admin.token / existingSecret / existingSecretKey | empty / empty / token | Admin bearer token, or a Secret that holds it |
gateway.auth.existingSecret / key | empty / userlist.txt | Client logins from a user list of "user" "SCRAM-SHA-256$..." lines |
gateway.tls.existingSecret | empty | A kubernetes.io/tls Secret for client TLS |
gateway.env | STREAMQL_DEFAULTS__MAX_SIZE: "20", STREAMQL_LOG__FORMAT: json | Extra STREAMQL_* settings |
gateway.config | empty | Optional TOML configuration; environment variables override it |
gateway.drain.* | preStopSeconds 5, endpointPropagationMs 2000, graceSeconds 30 | Graceful drain timings |
gateway.service.* | ClusterIP, port 6432, adminPort 9930 | Service type, ports, annotations, load balancer class and source ranges |
gateway.pdb.* | enabled, maxUnavailable 1 | Pod disruption budget |
gateway.zoneSpread.* | enabled, ScheduleAnyway | Topology spread across zones |
operator.enabled | false | Install the operator with the Gateway, Pool and Policy resources |
Platform values files are provided for OpenShift, EKS, AKS and GKE: values-openshift.yaml, values-eks.yaml, values-aks.yaml and values-gke.yaml. Matching kustomize overlays are in deploy/overlays.
Systemd#
packaging/systemd has streamql.service, streamql.socket, streamql-admin.socket and streamql-worker.service. The listen addresses come from the socket units, and sockets are passed to the process with socket activation, which also lets a new binary take over the listeners. packaging/streamql.toml is the starting configuration; every key can also be set as STREAMQL_<SECTION>__<KEY>, for example in /etc/streamql/streamql.env. Deb and rpm metadata is provided.
From source#
git clone https://github.com/streamql/streamql
cd streamql
cargo build --release # binary in target/release/streamql
docker build -t streamql . # container image
make image-pool-only # pooling only, without the consoleThe image is a static, non-root image that runs without a shell. --no-admin turns the admin API and console off at run time.
Verify the install#
streamql config validate
curl -s http://127.0.0.1:9930/readyz