CLI tool
psycopg/psycopg avatar
psycopg/psycopg

Psycopg 3: the PostgreSQL adapter that ships as three packages

New generation PostgreSQL database adapter for the Python programming language

2,509 stars284 forksPythonLGPL-3.0

At a glance

What is it?
One repository, three distributions, and a build configuration strict enough to type-check its own Cython extension. What the source tree says about running Psycopg in production.
Who is it for?
Psycopg 3 is the version to start on, and the repository makes the upgrade reasoning concrete rather than emotional: the pure Python package, the Cython speedup and the connection pool are versioned separately, so you can take the pool on a different cadence from the adapter. Two things decide whether this is painless for you.
Can I use it commercially?
Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One repository, three installable distributions

The thing that makes Psycopg's repository confusing on first contact is that it is not one package. It is three, and the README explains why before it explains anything else.

The psycopg directory holds the pure Python implementation. Its only runtime dependency is libpq, the PostgreSQL client library, which has to be present on the system rather than installed by pip. The psycopg_c directory holds an optimization module written in C and Cython, and building it needs a set of development tools whose details the README defers to the documentation. The psycopg_pool directory holds the connection pool implementations, and it is separated specifically so that it can follow a different release cycle from the adapter itself.

That separation is a design decision worth naming. A connection pool has a different risk profile from a database adapter: pools carry connection lifecycle and timeout behaviour, adapters carry protocol correctness. Letting them version independently means a pool fix does not force an adapter upgrade, and an adapter change does not drag a pool along with it.

For ordinary use none of this matters, because the published wheels bundle what you need:

bash
pip install "psycopg[binary,pool]"

The binary extra pulls prebuilt libpq so the compile step disappears, and the pool extra pulls psycopg_pool. If you want to see the dependency surface yourself, the README is unusually direct about it: the pure Python package has only libpq at runtime, and everything else is optional.

libpq is a platform requirement, not a Python dependency

The word binary in that install command is doing specific work, and it is worth understanding what it does and does not remove. It removes the need to compile against libpq at install time. It does not remove libpq as something your platform has to provide, which is why the README's Hacking section leads with getting it onto the machine.

On Debian and Ubuntu the library package is libpq5. On macOS it comes from Homebrew as libpq. On Windows the README points at EnterpriseDB's installers, which bundle libpq inside the PostgreSQL Command Line Tools. Each of those is a system-level step, and each is the step most likely to be forgotten by someone who expected a pure pip install.

This matters more in some deployment contexts than others. On a developer laptop the Homebrew or apt step happens once and is invisible afterwards. In a slim container image it is the difference between a working build and a missing-shared-object error at import time, and it is the reason the cross-compiling note at the end of the README exists: zipapps built with shiv that bundle Psycopg still need libpq on the target machine, because bundling a Python wheel does not bundle a C shared library.

The practical rule is that if your runtime image is distroless, Alpine without a libpq package, or a Windows container without the PostgreSQL tools, decide now how you are supplying libpq. The binary extra solves the build half of that problem and leaves the runtime half to you.

Strict mypy across Python and Cython, with named exclusions

The build configuration in pyproject.toml is the most informative file in the repository, and it says more about how this project is maintained than the README does. Mypy runs in strict mode, and the files list covers the pure Python package, the pool, the Cython extension and the tests together.

That last inclusion is unusual. Type-checking a Cython extension from a mypy run means the C module has to present consistent signatures to Python, and it is a meaningful amount of extra discipline. Two specific test modules are excluded from the mypy run: tests/test_tstring.py and tests/test_tstring_async.py. Those exclusions are about template string syntax, and their presence tells you the project hit a real limitation there and made a deliberate choice rather than leaving it to fail.

Three more decisions in that file are worth reading for what they reveal. First, sqlite_cache is explicitly disabled, with a comment explaining that SQLite's cache highlights mypy concurrency problems under parallel pre-commit runs. The comment links two specific mypy issues and says to check back in future to see whether a better approach has emerged. That is a maintainer leaving a note to themselves and to the next contributor.

Second, coverage is measured over the pure Python package and the pool but not the Cython extension, which is the normal consequence of measuring behaviour rather than compiled lines. Third, isort runs with the black profile, length_sort enabled and a nine-line output mode, so import order is not left to taste.

The test configuration is strict in a way that will surface environment differences immediately. Pytest is configured with filterwarnings set to error, which turns any warning into a failure, and testpaths pointed at tests. The README anticipates the result: it suggests excluding the proxy, subprocess and timing markers if some tests fail on a local host. That is a project telling you upfront that a clean run depends on your network and timing rather than on your checkout being wrong.

Running the tests means creating a database first

The test suite needs a real PostgreSQL instance, and the README gives the exact two commands rather than leaving it to a tox configuration. You create a database, point an environment variable at it, and then invoke pytest.

bash
psql -c 'create database psycopg_test'
export PSYCOPG_TEST_DSN="dbname=psycopg_test"
pytest

Note that PSYCOPG_TEST_DSN takes a libpq connection string rather than a URL, which is consistent with libpq being the substrate underneath everything here. If you would rather not run against a live server, the marker exclusions are the escape hatch:

bash
pytest  -m 'not proxy and not timing'

For contributors there is also the conventional commits requirement and a pre-commit setup step. The README asks you to run pre-commit install so that lint and type errors surface before you submit rather than during review. Given the strictness of the mypy configuration, that advice is worth following literally. The editable install sequence is given as well, and it carries a specific flag:

bash
pip install --config-settings editable_mode=strict -e "./psycopg[dev,test]"

The strict editable mode is a workaround for a setuptools problem that the README links directly. Contributors will hit it; anyone installing from a wheel will not.

No GitHub releases, so PyPI is the version history

This repository publishes zero GitHub releases. That is worth sitting with for a project with 2,504 stars, 280 forks and a commit history pushed as recently as late September 2026, because it means the tag-and-announcement workflow that most adopters expect simply is not part of this project's release process.

Nothing is wrong with that by itself. Plenty of mature libraries version exclusively on PyPI, and for a project whose install story is a wheel with bundled binaries, the PyPI page is arguably the only release page a user actually reads. The consequence for you is narrower and specific: the release notes you would normally skim on a releases page are not in this repository's visible history, so version-to-version change lists live on the project website instead. If you are auditing what changed between the version in your lock file and the version you are about to adopt, you are reading the psycopg.org documentation, not browsing GitHub.

There is one more consequence for tooling. Since there are no tags to speak of, anything that derives a version from git tags rather than from package metadata will see an unusual repository. Continuous integration systems that gate on release creation rather than on published packages need to be pointed at the package index instead.

The repository description itself also carries some age. Calling Psycopg 3 a new generation PostgreSQL database adapter describes a transition that is now well behind it, with a pure Python implementation, a Cython acceleration layer and a separately versioned pool all shipping in production. Read the tree and the build configuration for the current state; the one-line description is not a reliable summary.

Editorial conclusion

Psycopg 3 is the version to start on, and the repository makes the upgrade reasoning concrete rather than emotional: the pure Python package, the Cython speedup and the connection pool are versioned separately, so you can take the pool on a different cadence from the adapter. Two things decide whether this is painless for you. First, libpq is a real system dependency, and the binary extra exists to remove it from your build step but not from your platform requirements, which matters most on Windows and in slim container images. Second, there are no GitHub releases, so version history lives on PyPI and your dependency lock is the only record of what you run. If you want to contribute rather than just install, install the pre-commit hooks first: mypy runs in strict mode across all three packages including the Cython extension, and the hooks will tell you about a type error before a reviewer does.

Frequently asked questions

What is psycopg used for?

Psycopg is the PostgreSQL database adapter for Python, providing the interface Python programs use to connect to a PostgreSQL server and run queries. Version 3 of the adapter is described as a modern implementation and ships as three packages: psycopg, the psycopg_c Cython speedup, and psycopg_pool.

Which is better, psycopg or psycopg2?

This repository is Psycopg 3, the current line of the adapter, and it is a distinct implementation rather than a rename of psycopg2. The repository publishes no GitHub releases, so psycopg2's independent history is not visible here; the upgrade comparison belongs in the project's own documentation.

Does installing psycopg require libpq on the system?

Yes. The pure Python package has only one runtime dependency, libpq, and it must be installed on the operating system rather than by pip. The binary extra bundles libpq so you do not have to compile against it, but the library is still needed at runtime.

Why is the connection pool a separate package?

The README gives the reason directly: keeping psycopg_pool separate allows it to follow a different release cycle from the adapter. Install it alongside with the pool extra, as in pip install "psycopg[binary,pool]".

Official sources

  1. Issues
  2. License: LGPL-3.0
  3. Project website
  4. psycopg/psycopg on GitHub
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/psycopg-psycopg.svg)](https://hysenlabs.com/projects/psycopg-psycopg)