# rust-postgres: one wire protocol spread across nine published crates

> The rust-postgres repository is a Cargo workspace rather than a library. Deciding which of its nine crates you actually depend on, and reading the June 2026 releases as a pattern rather than three changelogs, tells you more about how to use it than the short README does.

**rust-postgres/rust-postgres** — Native PostgreSQL driver for the Rust programming language

- Repository: https://github.com/rust-postgres/rust-postgres
- Stars: 4,016 · Forks: 593
- Language: Rust
- License: Apache-2.0
- Published: 2026-10-08 · Updated: 2026-10-08 · Language: en
- Canonical page: https://hysenlabs.com/projects/rust-postgres-rust-postgres

## A workspace of nine crates, not a single library

Most Rust projects are one crate with one version and one dependency line. This one is a Cargo workspace, and the manifest at the root is the first fact worth internalising:

```toml
[workspace]
members = [
    "codegen",
    "postgres",
    "postgres-derive",
    "postgres-derive-test",
    "postgres-native-tls",
    "postgres-openssl",
    "postgres-protocol",
    "postgres-types",
    "tokio-postgres",
]
resolver = "2"
```

Nine members, resolver 2, and a release profile with `debug = 2` under `[profile.release]`, which keeps debug symbols in release builds so production stack traces from this driver are readable. That is a small signal about how the maintainers think about operating the thing.

Only five of the nine appear in the README. `postgres` is described as a native, synchronous PostgreSQL client, and `tokio-postgres` as a native, asynchronous PostgreSQL client, each with a docs.rs link and a crates.io version badge. `postgres-types` handles conversions between Rust and Postgres types. `postgres-native-tls` and `postgres-openssl` both provide TLS support for `postgres` and `tokio-postgres`, one through native-tls and one through openssl.

The four that the README leaves out are the interesting ones. `postgres-protocol` is the wire protocol implementation that the other two clients are built on, which is why `postgres` and `tokio-postgres` can agree on behaviour despite having different concurrency models. `postgres-derive` is a derive macro, and its `postgres-derive-test` member exists purely to test that macro. `codegen` generates parts of the implementation, which is how the type mapping stays consistent across releases without anyone typing it out by hand.

## Choosing between the sync and async clients

The split between `postgres` and `tokio-postgres` is the decision almost every new user of this repository makes first, and it is worth being deliberate about rather than reaching for the async one by habit.

Both speak the same PostgreSQL wire protocol through `postgres-protocol`, so the query language, the type conversions and the prepared-statement behaviour are the same. What differs is the runtime contract. The synchronous client blocks the thread it is called on, which is comfortable in a CLI, a batch job, or any code that is already single-threaded and does not have an executor to hand. The asynchronous client is built on Tokio and returns futures, which is what you want inside an application server where a blocked thread is a thread not serving someone else.

The version lines reinforce that these are maintained as siblings rather than one being a stub. The most recent releases, all published on 2026-06-12, are `tokio-postgres` at v0.7.18, `postgres` at v0.19.14, and `postgres-types` at v0.2.14. The async client is on 0.7 while the sync client is on 0.19, so their version numbers carry no relationship to each other and you cannot infer one from the other.

For TLS there is no third option, only a choice of backend. `postgres-native-tls` goes through the native-tls crate, which delegates to the platform TLS implementation on each operating system, so certificate handling follows whatever the OS provides. `postgres-openssl` links openssl directly, which gives you a predictable library version and a predictable configuration surface at the cost of shipping or linking openssl yourself. Both are documented as TLS support for `postgres` and `tokio-postgres`, so the choice is independent of the client choice.

This repository is a driver, not an ORM. There is no query builder, no schema migration tool and no connection pool in these nine crates. Whatever you pair it with for those jobs, you are pairing it with.

## The June 2026 releases are about not panicking

Three releases share the date 2026-06-12 and each is small enough to read in full, which makes them unusually useful evidence about how this driver handles bad input.

`tokio-postgres` v0.7.18 has one entry, a fix: error instead of panicking on a DataRow field and column count mismatch. A DataRow is the wire message carrying result rows, so this fires when a server returns a row whose column count disagrees with the statement description. That is a protocol-level inconsistency, and returning a typed error lets a caller decide whether to retry, fail the request or drop the connection. Panicking would have taken the task down, and in a server with a panic hook configured to abort, the process with it.

`postgres-types` v0.2.14 does two things. It adds a `FromSql` implementation for `Cow<str>`, which is a conversion from the database into a possibly-borrowed string and removes a manual conversion step for a very common column type. It also avoids a panic when decoding out-of-range `time` 0.2 date and timestamp values. The `time` crate's 0.2 line has a bounded range, so a timestamp from a database can legitimately exceed what that version can hold, and the fix is to surface that as an error rather than as a panic.

`postgres` v0.19.14 is the smallest of the three, with a single change: `tokio-postgres` updated to v0.7.18. Read as a set, the pattern is a driver tightening its error paths rather than adding features. Two of the three fixes convert a panic into an error, and the third is a type-conversion addition in the same crate that had just fixed a decode panic.

That matters more than a feature count would. A database driver sits on the boundary between your code and a system you do not control, and data arriving from that boundary can be old, malformed or simply larger than the type you expected. Converting those cases into errors is what lets the rest of your application handle them.

## Running the test suite means running PostgreSQL 18

The README's test instructions are the only operational content in the whole document, and they are six numbered steps: install `docker` and `docker-compose`, make sure your user has permissions for Docker, change to the top-level directory of the repository, run `docker-compose up -d`, run `cargo test`, then run `docker-compose stop`. The Ubuntu specifics are given inline, `sudo apt install docker.io docker-compose` and adding your user to the docker group with `sudo usermod -aG docker $USER`.

The configuration that gets started is a single service, and its `docker-compose.yml` is short enough to read as the environment contract for the test suite:

```yaml
version: '2'
services:
  postgres:
    image: docker.io/postgres:18
    ports:
      - 5433:5433
    volumes:
      - ./docker/sql_setup.sh:/docker-entrypoint-initdb.d/sql_setup.sh
    environment:
      POSTGRES_PASSWORD: postgres
```

Three details there will bite you if you skim. The image is PostgreSQL 18, not whatever you have installed locally. The port mapping is `5433:5433`, so the test database is not on the default 5432 and you will not collide with a local server, but any connection string you write has to say 5433. And the password is literally `postgres`, which is fine for a container on your own machine and is the reason the README is explicit that this is the easiest way to get a correctly configured instance rather than a way to configure one.

The volume mount is the fourth detail and it is the reason the setup is reproducible: `docker/sql_setup.sh` is mounted into `/docker-entrypoint-initdb.d/`, which the official image runs on first initialisation. Roles, types and any fixture data the tests assume are created by that script rather than by hand, so a missing file in `docker/` shows up as a test failure that looks nothing like a missing file.

## Licensing, maintenance state and what the numbers say

The repository carries two licence files, `LICENSE-APACHE` and `LICENSE-MIT`, and the licence field on the repository says Apache-2.0. In practice that means the Apache 2.0 text is the one to read, with the MIT grant available alongside it, which is a common and permissive arrangement for a library that ends up inside both open source and closed source products.

The maintenance picture is healthy in the ordinary sense and worth stating precisely rather than vaguely. The default branch is `master`, the repository is not archived, and the last push was on 2026-07-27, which is a little over two months before this evaluation. The release cadence implied by the June 2026 tags suggests the project ships when there is something to ship rather than on a schedule.

The number that deserves attention is open issues at 185 against 4,000 stars. On a repository of this size that is a normal-looking ratio, but it is worth knowing that issue responses on a driver of this kind are often answered with the PostgreSQL protocol documentation rather than with a code change. The driver implements what the server speaks; when a behaviour is surprising, the first question is usually which side is right.

There is no `CONTRIBUTING` guidance in the README and no roadmap in the repository root. The tree is composed of workspace manifests, the nine crate directories, `codegen/`, the test infrastructure in `test/` and `docker/`, plus CI and formatting configuration. For a project this size that is a complete picture, and what is missing from it is documentation that lives on docs.rs per crate rather than in the repository.

## Where this driver stops and another crate begins

Search interest around this repository clusters on one recurring question: rust-postgres versus sqlx. The driver itself does not answer that, and it is worth being explicit about the boundary so the comparison is made on the right terms.

What is here is a protocol implementation and a type conversion layer. `postgres-protocol` frames messages and reads them, `postgres-types` maps between Rust types and PostgreSQL type representations, and the two client crates give you that over a blocking or a future-returning interface. The `codegen` member exists so that the type mapping is generated rather than hand-maintained, and `postgres-derive` lets you attach metadata to your own types so the conversions follow your definitions instead of a registry.

What is not here is everything above that layer: no ORM, no compile-time-checked query macros, no connection pool, no migration runner, no query builder. A `Codegen` crate in a workspace like this one is internal tooling, not a public API for generating your own queries, and the README does not present it as one.

So the practical shape of a project built on rust-postgres is a small dependency doing a narrow job well, with pooling, migrations and query convenience supplied elsewhere. If you want that job done with fewer decisions, sqlx is the common alternative to evaluate, and the deciding question is usually how much you want compile-time query verification. If you want the protocol handled directly with predictable error behaviour and no macro layer between you and the wire, this workspace is the whole answer.

One practical note for reading the docs: they are on docs.rs per crate, so `docs.rs/postgres`, `docs.rs/tokio-postgres` and `docs.rs/postgres-types` are three different documents with three different audiences. The README treats them as links to equal-weight destinations; they are not.

## Conclusion

rust-postgres is not a crate you add, it is a family you choose from. `tokio-postgres` is the one most projects need, `postgres` is the synchronous counterpart for code that does not run on an executor, `postgres-types` is the conversion layer you meet through error messages before you meet it through docs, and `postgres-native-tls` or `postgres-openssl` decides how the connection is encrypted. The June 2026 releases, all on 2026-06-12, share one theme: two of the three fixes replace a panic with an error, one on a DataRow column count mismatch and one on out-of-range `time` 0.2 values. A driver that returns errors instead of unwinding is easier to run in production than one that does not, and that is the strongest signal in this repository. The README is 1,695 characters and installs nothing; the test suite needs Docker, PostgreSQL 18 on port 5433 and a password of `postgres`, so budget an afternoon before writing your first query.

## FAQ

### Should I use postgres or tokio-postgres?

Both speak the same PostgreSQL wire protocol through the shared `postgres-protocol` crate, so queries and type conversions behave the same. `postgres` is the native synchronous client and blocks the calling thread. `tokio-postgres` is the native asynchronous client and returns futures. Their versions are independent: `postgres` was at v0.19.14 and `tokio-postgres` at v0.7.18 as of the 2026-06-12 releases.

### How do I run the rust-postgres test suite?

Install docker and docker-compose, run `docker-compose up -d` from the top-level repository directory, then run `cargo test`, then `docker-compose stop`. The compose file starts `postgres:18` mapped on port 5433 with the password `postgres`, and mounts `docker/sql_setup.sh` into the image init directory so the fixtures the tests expect are created automatically.

### Is rust-postgres an ORM?

No. The workspace is a driver: a wire protocol implementation in `postgres-protocol`, Rust and PostgreSQL type conversions in `postgres-types`, and synchronous and asynchronous clients built on those. There is no query builder, no connection pool and no migration runner in the nine crates, so those layers come from elsewhere in your dependency tree.

### Which TLS backend should I use with rust-postgres?

Both are published for the same two clients. `postgres-native-tls` routes TLS through native-tls, which uses the operating system's own implementation, so certificate behaviour follows the platform. `postgres-openssl` links openssl directly, which gives you one predictable library version and configuration surface at the cost of providing openssl yourself.

## Sources

- [Issues](https://github.com/rust-postgres/rust-postgres/issues)
- [License: Apache-2.0](https://github.com/rust-postgres/rust-postgres/blob/master/LICENSE)
- [README](https://github.com/rust-postgres/rust-postgres/blob/master/README.md)
- [Releases](https://github.com/rust-postgres/rust-postgres/releases)
- [rust-postgres/rust-postgres on GitHub](https://github.com/rust-postgres/rust-postgres)

---

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