# SPQR: A Stateless Router for PostgreSQL Sharding

> SPQR is a Go-based PostgreSQL query router and pooler for distributing online workloads across shards. It is aimed at teams that need a PostgreSQL-compatible endpoint while moving from a monolithic database toward horizontal scaling.

**pg-sharding/spqr** — Stateless Postgres Query Router.

- Repository: https://github.com/pg-sharding/spqr
- Website: https://pg-sharding.tech
- Stars: 1,486 · Forks: 103
- Language: Go
- License: NOASSERTION
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/pg-sharding-spqr

## Why SPQR Sits Between PostgreSQL Clients and Shards

SPQR addresses a specific operational problem: a large PostgreSQL installation can become difficult to scale as its data volume and query load increase. The README describes the target as a single database holding terabytes of data and serving more than 100,000 queries per second. It presents SPQR as a production-ready system for horizontal PostgreSQL scaling through sharding.

The intended users are backend teams operating online PostgreSQL services, especially organizations that want to introduce sharding before rewriting every application component around a distributed data layer. The repository identifies SPQR as a stateless Postgres query router, and its topics include `pooler`, `postgres`, `proxy`, and `sharding`. The project therefore belongs at the connection and query-routing boundary, where existing PostgreSQL clients can remain in place while the backing topology changes.

That does not make migration automatic. SPQR still needs a defined routing model, shard metadata, connection policy, and operational process. The README does not document the complete semantics for arbitrary cross-shard transactions, conflict resolution, or every PostgreSQL feature. It also does not claim that SPQR is a general replacement for a distributed database whose consistency requirements differ from PostgreSQL's model.

## Router, Coordinator, Balancer, and Shard Data Flow

The repository layout shows several cooperating Go programs. `cmd/router` is compiled into `spqr-router`, while `cmd/coordinator` produces `spqr-coordinator` and `cmd/balancer` produces `spqr-balancer`. A `coorctl` command is also defined. The presence of separate binaries means SPQR is more than a single forwarding proxy embedded in one process.

The client-facing process is `spqr-router`. Its configuration comes from a file passed to the `run` command. The production Dockerfile documents port 6432 as the router port, 7432 as the admin console port, and 7000 as the gRPC API port. The Dockerfile health check connects to the admin console and executes `SHOW shards;`. This gives an operator a documented administrative query for checking the router's shard view, although the README does not define its output format or refresh behavior.

Examples include `localrouter.yaml`, `router.yaml`, `router_with_coordinator.yaml`, `shard_data.yaml`, separate coordinator and balancer configurations, and etcd-related files. This suggests several topology modes. The router may operate with configuration alone, with a coordinator, or with an external coordination service. The repository also includes `examples/1shardproxy.toml`, `examples/2shardproxy.json`, and YAML equivalents. The available documentation does not establish which combinations are mandatory, so installation should follow the selected example rather than assume that every component is optional or required.

The Docker Compose file builds PostgreSQL shard containers and exposes ports 7432, 7433, and additional ports. It defines replicas and sets `PG_SYNC_REPLICA: true`. That is a development topology, not a production sizing guide. Its port mappings can also collide with SPQR's documented ports when everything runs on one host.

## Building SPQR and Starting the Docker Example

The README provides two development paths. `make run` starts a quick Docker example, while local development requires the latest Go version. The Go module declares Go 1.26.0, and the production Dockerfile uses `golang:1.26-alpine` as its builder. The Makefile's default target downloads dependencies and creates a vendor directory, so the development environment must provide Go and the native tools required by the build.

The README lists the following build sequence. The documentation does not specify a particular success message, so the expected result is a successful command completion.

```bash
make
make build
```

The Makefile also provides a router-specific target. This target builds `spqr-router` with repository version metadata.

```bash
make build_router
```

After building, the documented launch syntax accepts a router configuration path. The README uses a placeholder, so it does not prescribe one universal filename.

```bash
spqr-router run --config path-to-router-config.yaml
```

The repository contains `examples/localrouter.yaml` and `examples/router.yaml`, but the README does not say that either example is appropriate unchanged for every environment. Operators must check the shard addresses, credentials, coordinator settings, ports, and data definitions in the selected file. The README also states that `make` runs unit, regression, and end-to-end tests, which require Docker Compose. It points to the `unittest`, `regress`, and `feature` sections of the Makefile for details.

## Configuration and Container Runtime Boundaries

The production Dockerfile uses a multi-stage build. Its builder stage installs Go build dependencies, downloads modules, and builds `spqr-router`. Its runtime stage uses Alpine 3.19 and installs `ca-certificates`, `tzdata`, and `postgresql-client`. The final image contains only the router binary and selected runtime dependencies, which reduces the image surface compared with a build image.

The runtime creates a `spqr` user and makes `/etc/spqr`, `/var/log/spqr`, and `/var/run/spqr` available to that user. It copies `examples/router.yaml` to `/etc/spqr/router.yaml.example`. Operators using volume mounts must account for the non-root execution context. A configuration file that is readable by an administrator but not by UID 1000 will not work with the packaged image, and a log directory that cannot be written will create a separate startup failure.

The image exposes the router, admin, and gRPC interfaces separately. The health check uses `psql -h localhost -p 7432 -U demo -d demo -c "SHOW shards;"`. The `demo` credentials appear in the Dockerfile health check, so they should be treated as image example settings rather than universal production credentials. Authentication examples are present, including `examples/auth_supported.yaml`, but the README does not document the complete authentication setup or credential rotation process.

The repository includes TOML, JSON, and YAML examples. The presence of multiple parsers in `go.mod` does not by itself establish which formats are accepted by every command. The selected command documentation and example file should control the decision.

## Operational Limits of a Stateless PostgreSQL Router

A PostgreSQL protocol endpoint is convenient, but it does not remove distributed-database constraints. SPQR must know the shard topology, route connections and queries according to configured rules, and expose administrative state that can be checked. Its health check confirms that the admin interface can answer `SHOW shards;`, yet the README does not define behavior during shard unavailability, coordinator failure, stale metadata, network partitions, or topology changes.

The repository includes a balancer, coordinator, monitoring and utility binaries, and unit, regression, and end-to-end tests. These are signs of a broad engineering surface, not a guarantee that every deployment mode has the same behavior or operational coverage. The term stateless describes the router architecture, not the entire system. Configuration, shard metadata, coordinator services, and balancer processes still form operational dependencies.

SPQR is the wrong tool when the application has no sharding requirement. Adding a router creates another network hop, configuration layer, authentication boundary, and possible failure domain. It is also a poor fit when cross-shard transactions require semantics that SPQR does not document. A team expecting a completely self-contained plug-in proxy may find the coordinator and topology-management requirements surprising.

The documentation also does not explain rollback, mixed-version operation, or schema migration steps. Those omissions matter for an online service because a router upgrade can coincide with changes to topology management and configuration interpretation.

## SPQR Maintenance, Upgrade Cost, and License Implications

The repository is not archived. Its last push was on 2026-10-16. Recent listed releases include 3.1.0 on 2026-08-28, 3.0.0 on 2026-06-19, and 2.9.9 on 2026-04-23. These dates show recent repository and release activity, but the README does not publish a compatibility policy or a complete upgrade procedure.

SPQR is written in Go, but the codebase contains multiple binaries rather than only the router. The Makefile includes targets for the router, balancer, coordinator, coordinator control tool, mover, monitor, dump utility, and workload replay. A production deployment may run only a subset, while contributors must account for the broader build and test surface. Local development is therefore not equivalent to compiling `spqr-router` alone.

The README states that the source code is distributed under the PostgreSQL Global Development Group License. GitHub classifies the repository license as custom, so the authoritative license text is the repository's `LICENSE` file. Teams should review that file for redistribution, modification, notice, and packaging obligations. This article identifies the license but does not provide legal advice.

Before upgrading, check the selected release against the coordinator, balancer, configuration examples, and PostgreSQL shard topology. The README does not document whether mixed versions are supported, so that point requires direct verification before a production rollout.

## Conclusion

SPQR fits teams that need a PostgreSQL-compatible route into a sharded topology, particularly during a gradual transition from one database deployment to several shards. It is a poor fit for a project that cannot take on router configuration, distributed routing state, and operational testing. Before adoption, verify routing behavior, coordinator requirements, authentication, failure handling, and the license text, then confirm that the selected example topology matches the intended deployment.

## FAQ

### What problem does SPQR solve?

SPQR is a stateless PostgreSQL query router for horizontal scaling through sharding. The README presents it as a way to serve large PostgreSQL deployments through a PostgreSQL-facing endpoint.

### How do I build and run the SPQR router?

The README lists `make` and `make build` for building. It then gives the launch syntax `spqr-router run --config path-to-router-config.yaml`.

### Which ports does the SPQR container expose?

The production Dockerfile documents port 6432 for the router, 7432 for the admin console, and 7000 for the gRPC API. Its health check connects to port 7432 and executes `SHOW shards;`.

## Sources

- [Issues](https://github.com/pg-sharding/spqr/issues)
- [pg-sharding/spqr on GitHub](https://github.com/pg-sharding/spqr)
- [Project website](https://pg-sharding.tech)
- [README](https://github.com/pg-sharding/spqr/blob/master/README.md)
- [Releases](https://github.com/pg-sharding/spqr/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pg-sharding-spqr
